diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..9a888adbb25 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# web + desktop packages +packages/app/ @adamdotdevin +packages/tauri/ @adamdotdevin +packages/desktop/ @adamdotdevin diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000000..fe1ec8409b4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,67 @@ +name: Bug report +description: Report an issue that should be fixed +labels: ["bug"] +body: + - type: textarea + id: description + attributes: + label: Description + description: Describe the bug you encountered + placeholder: What happened? + validations: + required: true + + - type: input + id: plugins + attributes: + label: Plugins + description: What plugins are you using? + validations: + required: false + + - type: input + id: opencode-version + attributes: + label: OpenCode version + description: What version of OpenCode are you using? + validations: + required: false + + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: How can we reproduce this issue? + placeholder: | + 1. + 2. + 3. + validations: + required: false + + - type: textarea + id: screenshot-or-link + attributes: + label: Screenshot and/or share link + description: Run `/share` to get a share link, or attach a screenshot + placeholder: Paste link or drag and drop screenshot here + validations: + required: false + + - type: input + id: os + attributes: + label: Operating System + description: what OS are you using? + placeholder: e.g., macOS 26.0.1, Ubuntu 22.04, Windows 11 + validations: + required: false + + - type: input + id: terminal + attributes: + label: Terminal + description: what terminal are you using? + placeholder: e.g., iTerm2, Ghostty, Alacritty, Windows Terminal + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..459ce25d05b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: 💬 Discord Community + url: https://discord.gg/opencode + about: For quick questions or real-time discussion. Note that issues are searchable and help others with the same question. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000000..92e6c47570a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,20 @@ +name: 🚀 Feature Request +description: Suggest an idea, feature, or enhancement +labels: [discussion] +title: "[FEATURE]:" + +body: + - type: checkboxes + id: verified + attributes: + label: Feature hasn't been suggested before. + options: + - label: I have verified this feature I'm about to request hasn't been suggested before. + required: true + + - type: textarea + attributes: + label: Describe the enhancement you want to request + description: What do you want to change or add? What are the benefits of implementing this? Try to be detailed so we can understand your request better :) + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 00000000000..2310bfcc86b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,11 @@ +name: Question +description: Ask a question +labels: ["question"] +body: + - type: textarea + id: question + attributes: + label: Question + description: What's your question? + validations: + required: true diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml new file mode 100644 index 00000000000..cba04faccef --- /dev/null +++ b/.github/actions/setup-bun/action.yml @@ -0,0 +1,22 @@ +name: "Setup Bun" +description: "Setup Bun with caching and install dependencies" +runs: + using: "composite" + steps: + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: package.json + + - name: Cache ~/.bun + id: cache-bun + uses: actions/cache@v4 + with: + path: ~/.bun + key: ${{ runner.os }}-bun-${{ hashFiles('package.json') }}-${{ hashFiles('bun.lockb', 'bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun-${{ hashFiles('package.json') }}- + + - name: Install dependencies + run: bun install + shell: bash diff --git a/.github/publish-python-sdk.yml b/.github/publish-python-sdk.yml new file mode 100644 index 00000000000..151ecb9944b --- /dev/null +++ b/.github/publish-python-sdk.yml @@ -0,0 +1,71 @@ +# +# This file is intentionally in the wrong dir, will move and add later.... +# + +# name: publish-python-sdk + +# on: +# release: +# types: [published] +# workflow_dispatch: + +# jobs: +# publish: +# runs-on: ubuntu-latest +# permissions: +# contents: read +# steps: +# - name: Checkout repository +# uses: actions/checkout@v4 + +# - name: Setup Bun +# uses: oven-sh/setup-bun@v1 +# with: +# bun-version: 1.2.21 + +# - name: Install dependencies (JS/Bun) +# run: bun install + +# - name: Install uv +# shell: bash +# run: curl -LsSf https://astral.sh/uv/install.sh | sh + +# - name: Generate Python SDK from OpenAPI (CLI) +# shell: bash +# run: | +# ~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli + +# - name: Sync Python dependencies +# shell: bash +# run: | +# ~/.local/bin/uv sync --dev --project packages/sdk/python + +# - name: Set version from release tag +# shell: bash +# run: | +# TAG="${GITHUB_REF_NAME:-}" +# if [ -z "$TAG" ]; then +# TAG="$(git describe --tags --abbrev=0 || echo 0.0.0)" +# fi +# echo "Using version: $TAG" +# VERSION="$TAG" ~/.local/bin/uv run --project packages/sdk/python python - <<'PY' +# import os, re, pathlib +# root = pathlib.Path('packages/sdk/python') +# pt = (root / 'pyproject.toml').read_text() +# version = os.environ.get('VERSION','0.0.0').lstrip('v') +# pt = re.sub(r'(?m)^(version\s*=\s*")[^"]+("\s*)$', f"\\1{version}\\2", pt) +# (root / 'pyproject.toml').write_text(pt) +# # Also update generator config override for consistency +# cfgp = root / 'openapi-python-client.yaml' +# if cfgp.exists(): +# cfg = cfgp.read_text() +# cfg = re.sub(r'(?m)^(package_version_override:\s*)\S+$', f"\\1{version}", cfg) +# cfgp.write_text(cfg) +# PY + +# - name: Build and publish to PyPI +# env: +# PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} +# shell: bash +# run: | +# ~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..b4369fa1a43 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,3 @@ +### What does this PR do? + +### How did you verify your code works? diff --git a/.github/workflows/daily-issues-recap.yml b/.github/workflows/daily-issues-recap.yml new file mode 100644 index 00000000000..a333e5365f9 --- /dev/null +++ b/.github/workflows/daily-issues-recap.yml @@ -0,0 +1,166 @@ +name: Daily Issues Recap + +on: + schedule: + # Run at 6 PM EST (23:00 UTC, or 22:00 UTC during daylight saving) + - cron: "0 23 * * *" + workflow_dispatch: # Allow manual trigger for testing + +jobs: + daily-recap: + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + issues: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup-bun + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Generate daily issues recap + id: recap + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENCODE_PERMISSION: | + { + "bash": { + "*": "deny", + "gh issue*": "allow", + "gh search*": "allow" + }, + "webfetch": "deny", + "edit": "deny", + "write": "deny" + } + run: | + # Get today's date range + TODAY=$(date -u +%Y-%m-%d) + + opencode run -m opencode/claude-sonnet-4-5 "Generate a daily issues recap for the OpenCode repository. + + TODAY'S DATE: ${TODAY} + + STEP 1: Gather today's issues + Search for all issues created today (${TODAY}) using: + gh issue list --repo ${{ github.repository }} --state all --search \"created:${TODAY}\" --json number,title,body,labels,state,comments,createdAt,author --limit 500 + + STEP 2: Analyze and categorize + For each issue created today, categorize it: + + **Severity Assessment:** + - CRITICAL: Crashes, data loss, security issues, blocks major functionality + - HIGH: Significant bugs affecting many users, important features broken + - MEDIUM: Bugs with workarounds, minor features broken + - LOW: Minor issues, cosmetic, nice-to-haves + + **Activity Assessment:** + - Note issues with high comment counts or engagement + - Note issues from repeat reporters (check if author has filed before) + + STEP 3: Cross-reference with existing issues + For issues that seem like feature requests or recurring bugs: + - Search for similar older issues to identify patterns + - Note if this is a frequently requested feature + - Identify any issues that are duplicates of long-standing requests + + STEP 4: Generate the recap + Create a structured recap with these sections: + + ===DISCORD_START=== + **Daily Issues Recap - ${TODAY}** + + **Summary Stats** + - Total issues opened today: [count] + - By category: [bugs/features/questions] + + **Critical/High Priority Issues** + [List any CRITICAL or HIGH severity issues with brief descriptions and issue numbers] + + **Most Active/Discussed** + [Issues with significant engagement or from active community members] + + **Trending Topics** + [Patterns noticed - e.g., 'Multiple reports about X', 'Continued interest in Y feature'] + + **Duplicates & Related** + [Issues that relate to existing open issues] + ===DISCORD_END=== + + STEP 5: Format for Discord + Format the recap as a Discord-compatible message: + - Use Discord markdown (**, __, etc.) + - BE EXTREMELY CONCISE - this is an EOD summary, not a detailed report + - Use hyperlinked issue numbers with suppressed embeds: [#1234]() + - Group related issues on single lines where possible + - Add emoji sparingly for critical items only + - HARD LIMIT: Keep under 1800 characters total + - Skip sections that have nothing notable (e.g., if no critical issues, omit that section) + - Prioritize signal over completeness - only surface what matters + + OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/recap_raw.txt + + # Extract only the Discord message between markers + sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/recap_raw.txt | grep -v '===DISCORD' > /tmp/recap.txt + + echo "recap_file=/tmp/recap.txt" >> $GITHUB_OUTPUT + + - name: Post to Discord + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} + run: | + if [ -z "$DISCORD_WEBHOOK_URL" ]; then + echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" + cat /tmp/recap.txt + exit 0 + fi + + # Read the recap + RECAP_RAW=$(cat /tmp/recap.txt) + RECAP_LENGTH=${#RECAP_RAW} + + echo "Recap length: ${RECAP_LENGTH} chars" + + # Function to post a message to Discord + post_to_discord() { + local msg="$1" + local content=$(echo "$msg" | jq -Rs '.') + curl -s -H "Content-Type: application/json" \ + -X POST \ + -d "{\"content\": ${content}}" \ + "$DISCORD_WEBHOOK_URL" + sleep 1 + } + + # If under limit, send as single message + if [ "$RECAP_LENGTH" -le 1950 ]; then + post_to_discord "$RECAP_RAW" + else + echo "Splitting into multiple messages..." + remaining="$RECAP_RAW" + while [ ${#remaining} -gt 0 ]; do + if [ ${#remaining} -le 1950 ]; then + post_to_discord "$remaining" + break + else + chunk="${remaining:0:1900}" + last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) + if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then + chunk="${remaining:0:$last_newline}" + remaining="${remaining:$((last_newline+1))}" + else + chunk="${remaining:0:1900}" + remaining="${remaining:1900}" + fi + post_to_discord "$chunk" + fi + done + fi + + echo "Posted daily recap to Discord" diff --git a/.github/workflows/daily-pr-recap.yml b/.github/workflows/daily-pr-recap.yml new file mode 100644 index 00000000000..7c8bab395f6 --- /dev/null +++ b/.github/workflows/daily-pr-recap.yml @@ -0,0 +1,169 @@ +name: Daily PR Recap + +on: + schedule: + # Run at 5pm EST (22:00 UTC, or 21:00 UTC during daylight saving) + - cron: "0 22 * * *" + workflow_dispatch: # Allow manual trigger for testing + +jobs: + pr-recap: + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + pull-requests: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup-bun + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Generate daily PR recap + id: recap + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENCODE_PERMISSION: | + { + "bash": { + "*": "deny", + "gh pr*": "allow", + "gh search*": "allow" + }, + "webfetch": "deny", + "edit": "deny", + "write": "deny" + } + run: | + TODAY=$(date -u +%Y-%m-%d) + + opencode run -m opencode/claude-sonnet-4-5 "Generate a daily PR activity recap for the OpenCode repository. + + TODAY'S DATE: ${TODAY} + + STEP 1: Gather PR data + Run these commands to gather PR information. ONLY include PRs created or updated TODAY (${TODAY}): + + # PRs created today + gh pr list --repo ${{ github.repository }} --state all --search \"created:${TODAY}\" --json number,title,author,labels,createdAt,updatedAt,reviewDecision,isDraft,additions,deletions --limit 100 + + # PRs with activity today (updated today) + gh pr list --repo ${{ github.repository }} --state open --search \"updated:${TODAY}\" --json number,title,author,labels,createdAt,updatedAt,reviewDecision,isDraft,additions,deletions --limit 100 + + + + STEP 2: For high-activity PRs, check comment counts + For promising PRs, run: + gh pr view [NUMBER] --repo ${{ github.repository }} --json comments --jq '[.comments[] | select(.author.login != \"copilot-pull-request-reviewer\" and .author.login != \"github-actions\")] | length' + + IMPORTANT: When counting comments/activity, EXCLUDE these bot accounts: + - copilot-pull-request-reviewer + - github-actions + + STEP 3: Identify what matters (ONLY from today's PRs) + + **Bug Fixes From Today:** + - PRs with 'fix' or 'bug' in title created/updated today + - Small bug fixes (< 100 lines changed) that are easy to review + - Bug fixes from community contributors + + **High Activity Today:** + - PRs with significant human comments today (excluding bots listed above) + - PRs with back-and-forth discussion today + + **Quick Wins:** + - Small PRs (< 50 lines) that are approved or nearly approved + - PRs that just need a final review + + STEP 4: Generate the recap + Create a structured recap: + + ===DISCORD_START=== + **Daily PR Recap - ${TODAY}** + + **New PRs Today** + [PRs opened today - group by type: bug fixes, features, etc.] + + **Active PRs Today** + [PRs with activity/updates today - significant discussion] + + **Quick Wins** + [Small PRs ready to merge] + ===DISCORD_END=== + + STEP 5: Format for Discord + - Use Discord markdown (**, __, etc.) + - BE EXTREMELY CONCISE - surface what we might miss + - Use hyperlinked PR numbers with suppressed embeds: [#1234]() + - Include PR author: [#1234]() (@author) + - For bug fixes, add brief description of what it fixes + - Show line count for quick wins: \"(+15/-3 lines)\" + - HARD LIMIT: Keep under 1800 characters total + - Skip empty sections + - Focus on PRs that need human eyes + + OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/pr_recap_raw.txt + + # Extract only the Discord message between markers + sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/pr_recap_raw.txt | grep -v '===DISCORD' > /tmp/pr_recap.txt + + echo "recap_file=/tmp/pr_recap.txt" >> $GITHUB_OUTPUT + + - name: Post to Discord + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} + run: | + if [ -z "$DISCORD_WEBHOOK_URL" ]; then + echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" + cat /tmp/pr_recap.txt + exit 0 + fi + + # Read the recap + RECAP_RAW=$(cat /tmp/pr_recap.txt) + RECAP_LENGTH=${#RECAP_RAW} + + echo "Recap length: ${RECAP_LENGTH} chars" + + # Function to post a message to Discord + post_to_discord() { + local msg="$1" + local content=$(echo "$msg" | jq -Rs '.') + curl -s -H "Content-Type: application/json" \ + -X POST \ + -d "{\"content\": ${content}}" \ + "$DISCORD_WEBHOOK_URL" + sleep 1 + } + + # If under limit, send as single message + if [ "$RECAP_LENGTH" -le 1950 ]; then + post_to_discord "$RECAP_RAW" + else + echo "Splitting into multiple messages..." + remaining="$RECAP_RAW" + while [ ${#remaining} -gt 0 ]; do + if [ ${#remaining} -le 1950 ]; then + post_to_discord "$remaining" + break + else + chunk="${remaining:0:1900}" + last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) + if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then + chunk="${remaining:0:$last_newline}" + remaining="${remaining:$((last_newline+1))}" + else + chunk="${remaining:0:1900}" + remaining="${remaining:1900}" + fi + post_to_discord "$chunk" + fi + done + fi + + echo "Posted daily PR recap to Discord" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a2e69410c8b..25466a63e06 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,17 +11,19 @@ concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: deploy: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - uses: actions/checkout@v3 - - uses: oven-sh/setup-bun@v1 - with: - bun-version: 1.2.19 + - uses: ./.github/actions/setup-bun - - run: bun install + - uses: actions/setup-node@v4 + with: + node-version: "24" - run: bun sst deploy --stage=${{ github.ref_name }} env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + PLANETSCALE_SERVICE_TOKEN_NAME: ${{ secrets.PLANETSCALE_SERVICE_TOKEN_NAME }} + PLANETSCALE_SERVICE_TOKEN: ${{ secrets.PLANETSCALE_SERVICE_TOKEN }} STRIPE_SECRET_KEY: ${{ github.ref_name == 'production' && secrets.STRIPE_SECRET_KEY_PROD || secrets.STRIPE_SECRET_KEY_DEV }} diff --git a/.github/workflows/docs-update.yml b/.github/workflows/docs-update.yml new file mode 100644 index 00000000000..a8dd2ae4f2b --- /dev/null +++ b/.github/workflows/docs-update.yml @@ -0,0 +1,72 @@ +name: Docs Update + +on: + schedule: + - cron: "0 */12 * * *" + workflow_dispatch: + +env: + LOOKBACK_HOURS: 4 + +jobs: + update-docs: + if: github.repository == 'sst/opencode' + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + id-token: write + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch full history to access commits + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Get recent commits + id: commits + run: | + COMMITS=$(git log --since="${{ env.LOOKBACK_HOURS }} hours ago" --pretty=format:"- %h %s" 2>/dev/null || echo "") + if [ -z "$COMMITS" ]; then + echo "No commits in the last ${{ env.LOOKBACK_HOURS }} hours" + echo "has_commits=false" >> $GITHUB_OUTPUT + else + echo "has_commits=true" >> $GITHUB_OUTPUT + { + echo "list<> $GITHUB_OUTPUT + fi + + - name: Run opencode + if: steps.commits.outputs.has_commits == 'true' + uses: sst/opencode/github@latest + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + with: + model: opencode/gpt-5.2 + agent: docs + prompt: | + Review the following commits from the last ${{ env.LOOKBACK_HOURS }} hours and identify any new features that may need documentation. + + + ${{ steps.commits.outputs.list }} + + + Steps: + 1. For each commit that looks like a new feature or significant change: + - Read the changed files to understand what was added + - Check if the feature is already documented in packages/web/src/content/docs/* + 2. If you find undocumented features: + - Update the relevant documentation files in packages/web/src/content/docs/* + - Follow the existing documentation style and structure + - Make sure to document the feature clearly with examples where appropriate + 3. If all new features are already documented, report that no updates are needed + 4. If you are creating a new documentation file be sure to update packages/web/astro.config.mjs too. + + Focus on user-facing features and API changes. Skip internal refactors, bug fixes, and test updates unless they affect user-facing behavior. + Don't feel the need to document every little thing. It is perfectly okay to make 0 changes at all. + Try to keep documentation only for large features or changes that already have a good spot to be documented. diff --git a/.github/workflows/duplicate-issues.yml b/.github/workflows/duplicate-issues.yml index 59f3f069660..53aa2a725eb 100644 --- a/.github/workflows/duplicate-issues.yml +++ b/.github/workflows/duplicate-issues.yml @@ -6,7 +6,7 @@ on: jobs: check-duplicates: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: contents: read issues: write @@ -16,23 +16,25 @@ jobs: with: fetch-depth: 1 + - uses: ./.github/actions/setup-bun + - name: Install opencode run: curl -fsSL https://opencode.ai/install | bash - name: Check for duplicate issues env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENCODE_PERMISSION: | { "bash": { - "gh issue*": "allow", - "*": "deny" - }, + "*": "deny", + "gh issue*": "allow" + }, "webfetch": "deny" } run: | - opencode run -m anthropic/claude-sonnet-4-20250514 "A new issue has been created: '${{ github.event.issue.title }}' + opencode run -m opencode/claude-haiku-4-5 "A new issue has been created:' Issue number: ${{ github.event.issue.number }} @@ -55,4 +57,7 @@ jobs: Feel free to ignore if none of these address your specific case.' + Additionally, if the issue mentions keybinds, keyboard shortcuts, or key bindings, please add a comment mentioning the pinned keybinds issue #4997: + 'For keybind-related issues, please also check our pinned keybinds documentation: #4997' + If no clear duplicates are found, do not comment." diff --git a/.github/workflows/duplicate-prs.yml b/.github/workflows/duplicate-prs.yml new file mode 100644 index 00000000000..32606858958 --- /dev/null +++ b/.github/workflows/duplicate-prs.yml @@ -0,0 +1,65 @@ +name: Duplicate PR Check + +on: + pull_request_target: + types: [opened] + +jobs: + check-duplicates: + if: | + github.event.pull_request.user.login != 'actions-user' && + github.event.pull_request.user.login != 'opencode' && + github.event.pull_request.user.login != 'rekram1-node' && + github.event.pull_request.user.login != 'thdxr' && + github.event.pull_request.user.login != 'kommander' && + github.event.pull_request.user.login != 'jayair' && + github.event.pull_request.user.login != 'fwang' && + github.event.pull_request.user.login != 'adamdotdevin' && + github.event.pull_request.user.login != 'iamdavidhill' && + github.event.pull_request.user.login != 'opencode-agent[bot]' + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Install dependencies + run: bun install + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Build prompt + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + { + echo "Check for duplicate PRs related to this new PR:" + echo "" + echo "CURRENT_PR_NUMBER: $PR_NUMBER" + echo "" + echo "Title: $(gh pr view "$PR_NUMBER" --json title --jq .title)" + echo "" + echo "Description:" + gh pr view "$PR_NUMBER" --json body --jq .body + } > pr_info.txt + + - name: Check for duplicate PRs + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + COMMENT=$(bun script/duplicate-pr.ts -f pr_info.txt "Check the attached file for PR details and search for duplicates") + + gh pr comment "$PR_NUMBER" --body "_The following comment was made by an LLM, it may be inaccurate:_ + + $COMMENT" diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml new file mode 100644 index 00000000000..29cc9895393 --- /dev/null +++ b/.github/workflows/generate.yml @@ -0,0 +1,51 @@ +name: generate + +on: + push: + branches: + - dev + workflow_dispatch: + +jobs: + generate: + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Generate + run: ./script/generate.ts + + - name: Commit and push + run: | + if [ -z "$(git status --porcelain)" ]; then + echo "No changes to commit" + exit 0 + fi + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add -A + git commit -m "chore: generate" + git push origin HEAD:${{ github.ref_name }} --no-verify + # if ! git push origin HEAD:${{ github.event.pull_request.head.ref || github.ref_name }} --no-verify; then + # echo "" + # echo "============================================" + # echo "Failed to push generated code." + # echo "Please run locally and push:" + # echo "" + # echo " ./script/generate.ts" + # echo " git add -A && git commit -m \"chore: generate\" && git push" + # echo "" + # echo "============================================" + # exit 1 + # fi diff --git a/.github/workflows/guidelines-check.yml b/.github/workflows/guidelines-check.yml deleted file mode 100644 index b4da51c93a1..00000000000 --- a/.github/workflows/guidelines-check.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Guidelines Check - -on: - # Disabled - uncomment to re-enable - # pull_request_target: - # types: [opened, synchronize] - -jobs: - check-guidelines: - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Check PR guidelines compliance - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENCODE_PERMISSION: '{ "bash": { "gh*": "allow", "gh pr review*": "deny", "*": "deny" } }' - run: | - opencode run -m anthropic/claude-sonnet-4-20250514 "A new pull request has been created: '${{ github.event.pull_request.title }}' - - - ${{ github.event.pull_request.number }} - - - - ${{ github.event.pull_request.body }} - - - Please check all the code changes in this pull request against the guidelines in AGENTS.md file in this repository. Diffs are important but make sure you read the entire file to get proper context. Make it clear the suggestions are merely suggestions and the human can decide what to do - - Use the gh cli to create comments on the files for the violations. Try to leave the comment on the exact line number. If you have a suggested fix include it in a suggestion code block. - - Command MUST be like this. - ``` - gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments \ - -f 'body=[summary of issue]' -f 'commit_id=${{ github.event.pull_request.head.sha }}' -f 'path=[path-to-file]' -F "line=[line]" -f 'side=RIGHT' - ``` - - Only create comments for actual violations. If the code follows all guidelines, don't run any gh commands." diff --git a/.github/workflows/nix-desktop.yml b/.github/workflows/nix-desktop.yml new file mode 100644 index 00000000000..3d7c4803133 --- /dev/null +++ b/.github/workflows/nix-desktop.yml @@ -0,0 +1,46 @@ +name: nix desktop + +on: + push: + branches: [dev] + paths: + - "flake.nix" + - "flake.lock" + - "nix/**" + - "packages/app/**" + - "packages/desktop/**" + - ".github/workflows/nix-desktop.yml" + pull_request: + paths: + - "flake.nix" + - "flake.lock" + - "nix/**" + - "packages/app/**" + - "packages/desktop/**" + - ".github/workflows/nix-desktop.yml" + workflow_dispatch: + +jobs: + build-desktop: + strategy: + fail-fast: false + matrix: + os: + - blacksmith-4vcpu-ubuntu-2404 + - blacksmith-4vcpu-ubuntu-2404-arm + - macos-15-intel + - macos-latest + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Nix + uses: nixbuild/nix-quick-install-action@v34 + + - name: Build desktop via flake + run: | + set -euo pipefail + nix --version + nix build .#desktop -L diff --git a/.github/workflows/notify-discord.yml b/.github/workflows/notify-discord.yml index c9032c301ee..62577ecf00e 100644 --- a/.github/workflows/notify-discord.yml +++ b/.github/workflows/notify-discord.yml @@ -2,11 +2,11 @@ name: discord on: release: - types: [published] # fires only when a release is published + types: [released] # fires when a draft release is published jobs: notify: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Send nicely-formatted embed to Discord uses: SethCohen/github-releases-to-discord@v1 diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml index cbe35f615bf..76e75fcaefb 100644 --- a/.github/workflows/opencode.yml +++ b/.github/workflows/opencode.yml @@ -3,6 +3,8 @@ name: opencode on: issue_comment: types: [created] + pull_request_review_comment: + types: [created] jobs: opencode: @@ -11,19 +13,22 @@ jobs: startsWith(github.event.comment.body, '/oc') || contains(github.event.comment.body, ' /opencode') || startsWith(github.event.comment.body, '/opencode') - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: - contents: read id-token: write + contents: read + pull-requests: read + issues: read steps: - name: Checkout repository uses: actions/checkout@v4 - with: - fetch-depth: 1 + + - uses: ./.github/actions/setup-bun - name: Run opencode - uses: sst/opencode/github@latest + uses: anomalyco/opencode/github@latest env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENCODE_PERMISSION: '{"bash": "deny"}' with: - model: anthropic/claude-sonnet-4-20250514 + model: opencode/claude-opus-4-5 diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml new file mode 100644 index 00000000000..c1cf1756787 --- /dev/null +++ b/.github/workflows/pr-standards.yml @@ -0,0 +1,139 @@ +name: PR Standards + +on: + pull_request_target: + types: [opened, edited, synchronize] + +jobs: + check-standards: + if: | + github.event.pull_request.user.login != 'actions-user' && + github.event.pull_request.user.login != 'opencode' && + github.event.pull_request.user.login != 'rekram1-node' && + github.event.pull_request.user.login != 'thdxr' && + github.event.pull_request.user.login != 'kommander' && + github.event.pull_request.user.login != 'jayair' && + github.event.pull_request.user.login != 'fwang' && + github.event.pull_request.user.login != 'adamdotdevin' && + github.event.pull_request.user.login != 'iamdavidhill' && + github.event.pull_request.user.login != 'opencode-agent[bot]' + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Check PR standards + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const title = pr.title; + + async function addLabel(label) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + labels: [label] + }); + } + + async function removeLabel(label) { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + name: label + }); + } catch (e) { + // Label wasn't present, ignore + } + } + + async function comment(marker, body) { + const markerText = ``; + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number + }); + + const existing = comments.find(c => c.body.includes(markerText)); + if (existing) return; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body: markerText + '\n' + body + }); + } + + // Step 1: Check title format + // Matches: feat:, feat(scope):, feat (scope):, etc. + const titlePattern = /^(feat|fix|docs|chore|refactor|test)\s*(\([a-zA-Z0-9-]+\))?\s*:/; + const hasValidTitle = titlePattern.test(title); + + if (!hasValidTitle) { + await addLabel('needs:title'); + await comment('title', `Hey! Your PR title \`${title}\` doesn't follow conventional commit format. + + Please update it to start with one of: + - \`feat:\` or \`feat(scope):\` new feature + - \`fix:\` or \`fix(scope):\` bug fix + - \`docs:\` or \`docs(scope):\` documentation changes + - \`chore:\` or \`chore(scope):\` maintenance tasks + - \`refactor:\` or \`refactor(scope):\` code refactoring + - \`test:\` or \`test(scope):\` adding or updating tests + + Where \`scope\` is the package name (e.g., \`app\`, \`desktop\`, \`opencode\`). + + See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#pr-titles) for details.`); + return; + } + + await removeLabel('needs:title'); + + // Step 2: Check for linked issue (skip for docs/refactor PRs) + const skipIssueCheck = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); + if (skipIssueCheck) { + await removeLabel('needs:issue'); + console.log('Skipping issue check for docs/refactor PR'); + return; + } + const query = ` + query($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $number) { + closingIssuesReferences(first: 1) { + totalCount + } + } + } + } + `; + + const result = await github.graphql(query, { + owner: context.repo.owner, + repo: context.repo.repo, + number: pr.number + }); + + const linkedIssues = result.repository.pullRequest.closingIssuesReferences.totalCount; + + if (linkedIssues === 0) { + await addLabel('needs:issue'); + await comment('issue', `Thanks for your contribution! + + This PR doesn't have a linked issue. All PRs must reference an existing issue. + + Please: + 1. Open an issue describing the bug/feature (if one doesn't exist) + 2. Add \`Fixes #\` or \`Closes #\` to this PR description + + See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#issue-first-policy) for details.`); + return; + } + + await removeLabel('needs:issue'); + console.log('PR meets all standards'); diff --git a/.github/workflows/publish-github-action.yml b/.github/workflows/publish-github-action.yml index cfd14148c3d..d2789373a34 100644 --- a/.github/workflows/publish-github-action.yml +++ b/.github/workflows/publish-github-action.yml @@ -14,7 +14,7 @@ permissions: jobs: publish: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - uses: actions/checkout@v3 with: diff --git a/.github/workflows/publish-vscode.yml b/.github/workflows/publish-vscode.yml index 5cb406f68c0..f49a1057807 100644 --- a/.github/workflows/publish-vscode.yml +++ b/.github/workflows/publish-vscode.yml @@ -13,22 +13,23 @@ permissions: jobs: publish: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: oven-sh/setup-bun@v2 - with: - bun-version: 1.2.19 + - uses: ./.github/actions/setup-bun - run: git fetch --force --tags - run: bun install -g @vscode/vsce + - name: Install extension dependencies + run: bun install + working-directory: ./sdks/vscode + - name: Publish run: | - bun install ./script/publish working-directory: ./sdks/vscode env: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cf9c547df89..8d7a823b144 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,27 +1,37 @@ name: publish -run-name: "${{ format('v{0}', inputs.version) }}" +run-name: "${{ format('release {0}', inputs.bump) }}" on: + push: + branches: + - dev + - snapshot-* workflow_dispatch: inputs: + bump: + description: "Bump major, minor, or patch" + required: false + type: choice + options: + - major + - minor + - patch version: - description: "Version to publish" - required: true - type: string - title: - description: "Custom title for this run" + description: "Override version (optional)" required: false type: string -concurrency: ${{ github.workflow }}-${{ github.ref }} +concurrency: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.version || inputs.bump }} permissions: + id-token: write contents: write packages: write jobs: publish: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 + if: github.repository == 'anomalyco/opencode' steps: - uses: actions/checkout@v3 with: @@ -29,44 +39,199 @@ jobs: - run: git fetch --force --tags - - uses: actions/setup-go@v5 + - uses: ./.github/actions/setup-bun + + - name: Install OpenCode + if: inputs.bump || inputs.version + run: bun i -g opencode-ai@1.0.169 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - uses: actions/setup-node@v4 + with: + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - name: Setup Git Identity + run: | + git config --global user.email "opencode@sst.dev" + git config --global user.name "opencode" + git remote set-url origin https://x-access-token:${{ secrets.SST_GITHUB_TOKEN }}@github.com/${{ github.repository }} + + - name: Publish + id: publish + run: ./script/publish-start.ts + env: + OPENCODE_BUMP: ${{ inputs.bump }} + OPENCODE_VERSION: ${{ inputs.version }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + AUR_KEY: ${{ secrets.AUR_KEY }} + GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} + NPM_CONFIG_PROVENANCE: false + + - uses: actions/upload-artifact@v4 with: - go-version: ">=1.24.0" - cache: true - cache-dependency-path: go.sum + name: opencode-cli + path: packages/opencode/dist - - uses: oven-sh/setup-bun@v2 + outputs: + release: ${{ steps.publish.outputs.release }} + tag: ${{ steps.publish.outputs.tag }} + version: ${{ steps.publish.outputs.version }} + + publish-tauri: + needs: publish + continue-on-error: false + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: x86_64-apple-darwin + - host: macos-latest + target: aarch64-apple-darwin + - host: blacksmith-4vcpu-windows-2025 + target: x86_64-pc-windows-msvc + - host: blacksmith-4vcpu-ubuntu-2404 + target: x86_64-unknown-linux-gnu + - host: blacksmith-4vcpu-ubuntu-2404-arm + target: aarch64-unknown-linux-gnu + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v3 with: - bun-version: 1.2.19 + fetch-depth: 0 + ref: ${{ needs.publish.outputs.tag }} - - name: Cache ~/.bun - id: cache-bun - uses: actions/cache@v3 + - uses: apple-actions/import-codesign-certs@v2 + if: ${{ runner.os == 'macOS' }} with: - path: ~/.bun - key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }} - restore-keys: | - ${{ runner.os }}-bun- + keychain: build + p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} + p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + + - name: Verify Certificate + if: ${{ runner.os == 'macOS' }} + run: | + CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application") + CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') + echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV + echo "Certificate imported." + + - name: Setup Apple API Key + if: ${{ runner.os == 'macOS' }} + run: | + echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8 + + - run: git fetch --force --tags + + - uses: ./.github/actions/setup-bun - - name: Install makepkg + - name: install dependencies (ubuntu only) + if: contains(matrix.settings.host, 'ubuntu') run: | sudo apt-get update - sudo apt-get install -y pacman-package-manager + sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf + + - name: install Rust stable + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.settings.target }} + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: packages/desktop/src-tauri + shared-key: ${{ matrix.settings.target }} + + - name: Prepare + run: | + cd packages/desktop + bun ./scripts/prepare.ts + env: + OPENCODE_VERSION: ${{ needs.publish.outputs.version }} + NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} + GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} + AUR_KEY: ${{ secrets.AUR_KEY }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + RUST_TARGET: ${{ matrix.settings.target }} + GH_TOKEN: ${{ github.token }} + GITHUB_RUN_ID: ${{ github.run_id }} + + # Fixes AppImage build issues, can be removed when https://github.com/tauri-apps/tauri/pull/12491 is released + - name: Install tauri-cli from portable appimage branch + if: contains(matrix.settings.host, 'ubuntu') + run: | + cargo install tauri-cli --git https://github.com/tauri-apps/tauri --branch feat/truly-portable-appimage --force + echo "Installed tauri-cli version:" + cargo tauri --version + + - name: Build and upload artifacts + uses: Wandalen/wretry.action@v3 + timeout-minutes: 60 + with: + attempt_limit: 3 + attempt_delay: 10000 + action: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a + with: | + projectPath: packages/desktop + uploadWorkflowArtifacts: true + tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }} + args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose + updaterJsonPreferNsis: true + releaseId: ${{ needs.publish.outputs.release }} + tagName: ${{ needs.publish.outputs.tag }} + releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext] + releaseDraft: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} + APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8 + + publish-release: + needs: + - publish + - publish-tauri + if: needs.publish.outputs.tag + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ needs.publish.outputs.tag }} + + - uses: ./.github/actions/setup-bun + - name: Setup SSH for AUR run: | + sudo apt-get update + sudo apt-get install -y pacman-package-manager mkdir -p ~/.ssh echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa git config --global user.email "opencode@sst.dev" git config --global user.name "opencode" ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true - - name: Install dependencies - run: bun install - - name: Publish - run: | - OPENCODE_VERSION=${{ inputs.version }} ./script/publish.ts + - run: ./script/publish-complete.ts env: - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} + OPENCODE_VERSION: ${{ needs.publish.outputs.version }} AUR_KEY: ${{ secrets.AUR_KEY }} - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} + GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} diff --git a/.github/workflows/release-github-action.yml b/.github/workflows/release-github-action.yml new file mode 100644 index 00000000000..3f5caa55c8d --- /dev/null +++ b/.github/workflows/release-github-action.yml @@ -0,0 +1,29 @@ +name: release-github-action + +on: + push: + branches: + - dev + paths: + - "github/**" + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + +jobs: + release: + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: git fetch --force --tags + + - name: Release + run: | + git config --global user.email "opencode@sst.dev" + git config --global user.name "opencode" + ./github/script/release diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml new file mode 100644 index 00000000000..93b01bafa2b --- /dev/null +++ b/.github/workflows/review.yml @@ -0,0 +1,83 @@ +name: Guidelines Check + +on: + issue_comment: + types: [created] + +jobs: + check-guidelines: + if: | + github.event.issue.pull_request && + startsWith(github.event.comment.body, '/review') && + contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association) + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + pull-requests: write + steps: + - name: Get PR number + id: pr-number + run: | + if [ "${{ github.event_name }}" = "pull_request_target" ]; then + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + else + echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT + fi + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup-bun + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Get PR details + id: pr-details + run: | + gh api /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }} > pr_data.json + echo "title=$(jq -r .title pr_data.json)" >> $GITHUB_OUTPUT + echo "sha=$(jq -r .head.sha pr_data.json)" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check PR guidelines compliance + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENCODE_PERMISSION: '{ "bash": { "*": "deny", "gh*": "allow", "gh pr review*": "deny" } }' + PR_TITLE: ${{ steps.pr-details.outputs.title }} + run: | + PR_BODY=$(jq -r .body pr_data.json) + opencode run -m anthropic/claude-opus-4-5 "A new pull request has been created: '${PR_TITLE}' + + + ${{ steps.pr-number.outputs.number }} + + + + $PR_BODY + + + Please check all the code changes in this pull request against the style guide, also look for any bugs if they exist. Diffs are important but make sure you read the entire file to get proper context. Make it clear the suggestions are merely suggestions and the human can decide what to do + + When critiquing code against the style guide, be sure that the code is ACTUALLY in violation, don't complain about else statements if they already use early returns there. You may complain about excessive nesting though, regardless of else statement usage. + When critiquing code style don't be a zealot, we don't like "let" statements but sometimes they are the simplest option, if someone does a bunch of nesting with let, they should consider using iife (see packages/opencode/src/util.iife.ts) + + Use the gh cli to create comments on the files for the violations. Try to leave the comment on the exact line number. If you have a suggested fix include it in a suggestion code block. + If you are writing suggested fixes, BE SURE THAT the change you are recommending is actually valid typescript, often I have seen missing closing "}" or other syntax errors. + Generally, write a comment instead of writing suggested change if you can help it. + + Command MUST be like this. + \`\`\` + gh api \ + --method POST \ + -H \"Accept: application/vnd.github+json\" \ + -H \"X-GitHub-Api-Version: 2022-11-28\" \ + /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }}/comments \ + -f 'body=[summary of issue]' -f 'commit_id=${{ steps.pr-details.outputs.sha }}' -f 'path=[path-to-file]' -F \"line=[line]\" -f 'side=RIGHT' + \`\`\` + + Only create comments for actual violations. If the code follows all guidelines, comment on the issue using gh cli: 'lgtm' AND NOTHING ELSE!!!!." diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml new file mode 100644 index 00000000000..b5378d7d527 --- /dev/null +++ b/.github/workflows/stale-issues.yml @@ -0,0 +1,33 @@ +name: "Auto-close stale issues" + +on: + schedule: + - cron: "30 1 * * *" # Daily at 1:30 AM + workflow_dispatch: + +env: + DAYS_BEFORE_STALE: 90 + DAYS_BEFORE_CLOSE: 7 + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/stale@v10 + with: + days-before-stale: ${{ env.DAYS_BEFORE_STALE }} + days-before-close: ${{ env.DAYS_BEFORE_CLOSE }} + stale-issue-label: "stale" + close-issue-message: | + [automated] Closing due to ${{ env.DAYS_BEFORE_STALE }}+ days of inactivity. + + Feel free to reopen if you still need this! + stale-issue-message: | + [automated] This issue has had no activity for ${{ env.DAYS_BEFORE_STALE }} days. + + It will be closed in ${{ env.DAYS_BEFORE_CLOSE }} days if there's no new activity. + remove-stale-when-updated: true + exempt-issue-labels: "pinned,security,feature-request,on-hold" + start-date: "2025-12-27" diff --git a/.github/workflows/stats.yml b/.github/workflows/stats.yml index ab7f24e2786..824733901d6 100644 --- a/.github/workflows/stats.yml +++ b/.github/workflows/stats.yml @@ -5,9 +5,12 @@ on: - cron: "0 12 * * *" # Run daily at 12:00 UTC workflow_dispatch: # Allow manual trigger +concurrency: ${{ github.workflow }}-${{ github.ref }} + jobs: stats: - runs-on: ubuntu-latest + if: github.repository == 'anomalyco/opencode' + runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: contents: write @@ -16,9 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest + uses: ./.github/actions/setup-bun - name: Run stats script run: bun script/stats.ts diff --git a/.github/workflows/sync-zed-extension.yml b/.github/workflows/sync-zed-extension.yml new file mode 100644 index 00000000000..f14487cde97 --- /dev/null +++ b/.github/workflows/sync-zed-extension.yml @@ -0,0 +1,35 @@ +name: "sync-zed-extension" + +on: + workflow_dispatch: + release: + types: [published] + +jobs: + zed: + name: Release Zed Extension + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: ./.github/actions/setup-bun + + - name: Get version tag + id: get_tag + run: | + if [ "${{ github.event_name }}" = "release" ]; then + TAG="${{ github.event.release.tag_name }}" + else + TAG=$(git tag --list 'v[0-9]*.*' --sort=-version:refname | head -n 1) + fi + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "Using tag: ${TAG}" + + - name: Sync Zed extension + run: | + ./script/sync-zed.ts ${{ steps.get_tag.outputs.tag }} + env: + ZED_EXTENSIONS_PAT: ${{ secrets.ZED_EXTENSIONS_PAT }} + ZED_PR_PAT: ${{ secrets.ZED_PR_PAT }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000000..fcbf9569f57 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,147 @@ +name: test + +on: + push: + branches: + - dev + pull_request: + workflow_dispatch: +jobs: + test: + name: test (${{ matrix.settings.name }}) + strategy: + fail-fast: false + matrix: + settings: + - name: linux + host: blacksmith-4vcpu-ubuntu-2404 + playwright: bunx playwright install --with-deps + workdir: . + command: | + git config --global user.email "bot@opencode.ai" + git config --global user.name "opencode" + bun turbo typecheck + bun turbo test + - name: windows + host: windows-latest + playwright: bunx playwright install + workdir: packages/app + command: bun test:e2e:local + runs-on: ${{ matrix.settings.host }} + defaults: + run: + shell: bash + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Install Playwright browsers + working-directory: packages/app + run: ${{ matrix.settings.playwright }} + + - name: Set OS-specific paths + run: | + if [ "${{ runner.os }}" = "Windows" ]; then + printf '%s\n' "OPENCODE_E2E_ROOT=${{ runner.temp }}\\opencode-e2e" >> "$GITHUB_ENV" + printf '%s\n' "OPENCODE_TEST_HOME=${{ runner.temp }}\\opencode-e2e\\home" >> "$GITHUB_ENV" + printf '%s\n' "XDG_DATA_HOME=${{ runner.temp }}\\opencode-e2e\\share" >> "$GITHUB_ENV" + printf '%s\n' "XDG_CACHE_HOME=${{ runner.temp }}\\opencode-e2e\\cache" >> "$GITHUB_ENV" + printf '%s\n' "XDG_CONFIG_HOME=${{ runner.temp }}\\opencode-e2e\\config" >> "$GITHUB_ENV" + printf '%s\n' "XDG_STATE_HOME=${{ runner.temp }}\\opencode-e2e\\state" >> "$GITHUB_ENV" + printf '%s\n' "MODELS_DEV_API_JSON=${{ github.workspace }}\\packages\\opencode\\test\\tool\\fixtures\\models-api.json" >> "$GITHUB_ENV" + else + printf '%s\n' "OPENCODE_E2E_ROOT=${{ runner.temp }}/opencode-e2e" >> "$GITHUB_ENV" + printf '%s\n' "OPENCODE_TEST_HOME=${{ runner.temp }}/opencode-e2e/home" >> "$GITHUB_ENV" + printf '%s\n' "XDG_DATA_HOME=${{ runner.temp }}/opencode-e2e/share" >> "$GITHUB_ENV" + printf '%s\n' "XDG_CACHE_HOME=${{ runner.temp }}/opencode-e2e/cache" >> "$GITHUB_ENV" + printf '%s\n' "XDG_CONFIG_HOME=${{ runner.temp }}/opencode-e2e/config" >> "$GITHUB_ENV" + printf '%s\n' "XDG_STATE_HOME=${{ runner.temp }}/opencode-e2e/state" >> "$GITHUB_ENV" + printf '%s\n' "MODELS_DEV_API_JSON=${{ github.workspace }}/packages/opencode/test/tool/fixtures/models-api.json" >> "$GITHUB_ENV" + fi + + - name: Seed opencode data + if: matrix.settings.name != 'windows' + working-directory: packages/opencode + run: bun script/seed-e2e.ts + env: + MODELS_DEV_API_JSON: ${{ env.MODELS_DEV_API_JSON }} + OPENCODE_DISABLE_MODELS_FETCH: "true" + OPENCODE_DISABLE_SHARE: "true" + OPENCODE_DISABLE_LSP_DOWNLOAD: "true" + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true" + OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true" + OPENCODE_TEST_HOME: ${{ env.OPENCODE_TEST_HOME }} + XDG_DATA_HOME: ${{ env.XDG_DATA_HOME }} + XDG_CACHE_HOME: ${{ env.XDG_CACHE_HOME }} + XDG_CONFIG_HOME: ${{ env.XDG_CONFIG_HOME }} + XDG_STATE_HOME: ${{ env.XDG_STATE_HOME }} + OPENCODE_E2E_PROJECT_DIR: ${{ github.workspace }} + OPENCODE_E2E_SESSION_TITLE: "E2E Session" + OPENCODE_E2E_MESSAGE: "Seeded for UI e2e" + OPENCODE_E2E_MODEL: "opencode/gpt-5-nano" + + - name: Run opencode server + if: matrix.settings.name != 'windows' + working-directory: packages/opencode + run: bun dev -- --print-logs --log-level WARN serve --port 4096 --hostname 127.0.0.1 & + env: + MODELS_DEV_API_JSON: ${{ env.MODELS_DEV_API_JSON }} + OPENCODE_DISABLE_MODELS_FETCH: "true" + OPENCODE_DISABLE_SHARE: "true" + OPENCODE_DISABLE_LSP_DOWNLOAD: "true" + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true" + OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true" + OPENCODE_TEST_HOME: ${{ env.OPENCODE_TEST_HOME }} + XDG_DATA_HOME: ${{ env.XDG_DATA_HOME }} + XDG_CACHE_HOME: ${{ env.XDG_CACHE_HOME }} + XDG_CONFIG_HOME: ${{ env.XDG_CONFIG_HOME }} + XDG_STATE_HOME: ${{ env.XDG_STATE_HOME }} + OPENCODE_CLIENT: "app" + + - name: Wait for opencode server + if: matrix.settings.name != 'windows' + run: | + for i in {1..120}; do + curl -fsS "http://127.0.0.1:4096/global/health" > /dev/null && exit 0 + sleep 1 + done + exit 1 + + - name: run + working-directory: ${{ matrix.settings.workdir }} + run: ${{ matrix.settings.command }} + env: + CI: true + MODELS_DEV_API_JSON: ${{ env.MODELS_DEV_API_JSON }} + OPENCODE_DISABLE_MODELS_FETCH: "true" + OPENCODE_DISABLE_SHARE: "true" + OPENCODE_DISABLE_LSP_DOWNLOAD: "true" + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true" + OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true" + OPENCODE_TEST_HOME: ${{ env.OPENCODE_TEST_HOME }} + XDG_DATA_HOME: ${{ env.XDG_DATA_HOME }} + XDG_CACHE_HOME: ${{ env.XDG_CACHE_HOME }} + XDG_CONFIG_HOME: ${{ env.XDG_CONFIG_HOME }} + XDG_STATE_HOME: ${{ env.XDG_STATE_HOME }} + PLAYWRIGHT_SERVER_HOST: "127.0.0.1" + PLAYWRIGHT_SERVER_PORT: "4096" + VITE_OPENCODE_SERVER_HOST: "127.0.0.1" + VITE_OPENCODE_SERVER_PORT: "4096" + OPENCODE_CLIENT: "app" + timeout-minutes: 30 + + - name: Upload Playwright artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-${{ matrix.settings.name }}-${{ github.run_attempt }} + if-no-files-found: ignore + retention-days: 7 + path: | + packages/app/e2e/test-results + packages/app/e2e/playwright-report diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml new file mode 100644 index 00000000000..6e150957291 --- /dev/null +++ b/.github/workflows/triage.yml @@ -0,0 +1,37 @@ +name: Issue Triage + +on: + issues: + types: [opened] + +jobs: + triage: + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + issues: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Triage issue + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + ISSUE_TITLE: ${{ github.event.issue.title }} + ISSUE_BODY: ${{ github.event.issue.body }} + run: | + opencode run --agent triage "The following issue was just opened, triage it: + + Title: $ISSUE_TITLE + + $ISSUE_BODY" diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 01aa398b55d..011e23f5f6f 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -1,4 +1,4 @@ -name: Typecheck +name: typecheck on: pull_request: @@ -7,18 +7,13 @@ on: jobs: typecheck: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Bun - uses: oven-sh/setup-bun@v1 - with: - bun-version: 1.2.19 - - - name: Install dependencies - run: bun install + uses: ./.github/actions/setup-bun - name: Run typecheck run: bun typecheck diff --git a/.github/workflows/update-nix-hashes.yml b/.github/workflows/update-nix-hashes.yml new file mode 100644 index 00000000000..7175f4fbdd6 --- /dev/null +++ b/.github/workflows/update-nix-hashes.yml @@ -0,0 +1,138 @@ +name: Update Nix Hashes + +permissions: + contents: write + +on: + workflow_dispatch: + push: + paths: + - "bun.lock" + - "package.json" + - "packages/*/package.json" + - "flake.lock" + - ".github/workflows/update-nix-hashes.yml" + pull_request: + paths: + - "bun.lock" + - "package.json" + - "packages/*/package.json" + - "flake.lock" + - ".github/workflows/update-nix-hashes.yml" + +jobs: + update-node-modules-hashes: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + runs-on: blacksmith-4vcpu-ubuntu-2404 + env: + TITLE: node_modules hashes + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + ref: ${{ github.head_ref || github.ref_name }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + + - name: Setup Nix + uses: nixbuild/nix-quick-install-action@v34 + + - name: Configure git + run: | + git config --global user.email "action@github.com" + git config --global user.name "Github Action" + + - name: Pull latest changes + env: + TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} + run: | + BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}" + git pull --rebase --autostash origin "$BRANCH" + + - name: Compute all node_modules hashes + run: | + set -euo pipefail + + HASH_FILE="nix/hashes.json" + SYSTEMS="x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin" + + if [ ! -f "$HASH_FILE" ]; then + mkdir -p "$(dirname "$HASH_FILE")" + echo '{"nodeModules":{}}' > "$HASH_FILE" + fi + + for SYSTEM in $SYSTEMS; do + echo "Computing hash for ${SYSTEM}..." + BUILD_LOG=$(mktemp) + trap 'rm -f "$BUILD_LOG"' EXIT + + # The updater derivations use fakeHash, so they will fail and reveal the correct hash + UPDATER_ATTR=".#packages.x86_64-linux.${SYSTEM}_node_modules" + + nix build "$UPDATER_ATTR" --no-link 2>&1 | tee "$BUILD_LOG" || true + + CORRECT_HASH="$(grep -E 'got:\s+sha256-[A-Za-z0-9+/=]+' "$BUILD_LOG" | awk '{print $2}' | head -n1 || true)" + + if [ -z "$CORRECT_HASH" ]; then + CORRECT_HASH="$(grep -A2 'hash mismatch' "$BUILD_LOG" | grep 'got:' | awk '{print $2}' | sed 's/sha256:/sha256-/' || true)" + fi + + if [ -z "$CORRECT_HASH" ]; then + echo "Failed to determine correct node_modules hash for ${SYSTEM}." + cat "$BUILD_LOG" + exit 1 + fi + + echo " ${SYSTEM}: ${CORRECT_HASH}" + jq --arg sys "$SYSTEM" --arg h "$CORRECT_HASH" \ + '.nodeModules[$sys] = $h' "$HASH_FILE" > "${HASH_FILE}.tmp" + mv "${HASH_FILE}.tmp" "$HASH_FILE" + done + + echo "All hashes computed:" + cat "$HASH_FILE" + + - name: Commit ${{ env.TITLE }} changes + env: + TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} + run: | + set -euo pipefail + + HASH_FILE="nix/hashes.json" + echo "Checking for changes..." + + summarize() { + local status="$1" + { + echo "### Nix $TITLE" + echo "" + echo "- ref: ${GITHUB_REF_NAME}" + echo "- status: ${status}" + } >> "$GITHUB_STEP_SUMMARY" + if [ -n "${GITHUB_SERVER_URL:-}" ] && [ -n "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_RUN_ID:-}" ]; then + echo "- run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" >> "$GITHUB_STEP_SUMMARY" + fi + echo "" >> "$GITHUB_STEP_SUMMARY" + } + + FILES=("$HASH_FILE") + STATUS="$(git status --short -- "${FILES[@]}" || true)" + if [ -z "$STATUS" ]; then + echo "No changes detected." + summarize "no changes" + exit 0 + fi + + echo "Changes detected:" + echo "$STATUS" + git add "${FILES[@]}" + git commit -m "chore: update nix node_modules hashes" + + BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}" + git pull --rebase --autostash origin "$BRANCH" + git push origin HEAD:"$BRANCH" + echo "Changes pushed successfully" + + summarize "committed $(git rev-parse --short HEAD)" diff --git a/.gitignore b/.gitignore index 33e3deb8184..78a77f81982 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,28 @@ .DS_Store node_modules +.worktrees .sst .env .idea .vscode -openapi.json +*~ playground tmp +dist +ts-dist +.turbo +**/.serena +.serena/ +/result +refs +Session.vim +opencode.json +a.out +target +.scripts +.direnv/ + +# Local dev files +opencode-dev +logs/ +*.bun-build diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 00000000000..5d3cc53411b --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,20 @@ +#!/bin/sh +set -e +# Check if bun version matches package.json +# keep in sync with packages/script/src/index.ts semver qualifier +bun -e ' +import { semver } from "bun"; +const pkg = await Bun.file("package.json").json(); +const expectedBunVersion = pkg.packageManager?.split("@")[1]; +if (!expectedBunVersion) { + throw new Error("packageManager field not found in root package.json"); +} +const expectedBunVersionRange = `^${expectedBunVersion}`; +if (!semver.satisfies(process.versions.bun, expectedBunVersionRange)) { + throw new Error(`This script requires bun@${expectedBunVersionRange}, but you are using bun@${process.versions.bun}`); +} +if (process.versions.bun !== expectedBunVersion) { + console.warn(`Warning: Bun version ${process.versions.bun} differs from expected ${expectedBunVersion}`); +} +' +bun typecheck diff --git a/.opencode/.gitignore b/.opencode/.gitignore new file mode 100644 index 00000000000..00bfdfda298 --- /dev/null +++ b/.opencode/.gitignore @@ -0,0 +1,3 @@ +plans/ +bun.lock +package.json diff --git a/.opencode/agent/docs.md b/.opencode/agent/docs.md index 7f974375693..21cfc6a16e0 100644 --- a/.opencode/agent/docs.md +++ b/.opencode/agent/docs.md @@ -1,11 +1,14 @@ --- description: ALWAYS use this when writing docs +color: "#38A3EE" --- You are an expert technical documentation writer You are not verbose +Use a relaxed and friendly tone + The title of the page should be a word or a 2-3 word phrase The description should be one short line, should not start with "The", should @@ -13,7 +16,7 @@ avoid repeating the title of the page, should be 5-10 words long Chunks of text should not be more than 2 sentences long -Each section is spearated by a divider of 3 dashes +Each section is separated by a divider of 3 dashes The section titles are short with only the first letter of the word capitalized @@ -27,3 +30,5 @@ Check out the /packages/web/src/content/docs/docs/index.mdx as an example. For JS or TS code snippets remove trailing semicolons and any trailing commas that might not be needed. + +If you are making a commit prefix the commit message with `docs:` diff --git a/.opencode/agent/duplicate-pr.md b/.opencode/agent/duplicate-pr.md new file mode 100644 index 00000000000..c9c932ef790 --- /dev/null +++ b/.opencode/agent/duplicate-pr.md @@ -0,0 +1,26 @@ +--- +mode: primary +hidden: true +model: opencode/claude-haiku-4-5 +color: "#E67E22" +tools: + "*": false + "github-pr-search": true +--- + +You are a duplicate PR detection agent. When a PR is opened, your job is to search for potentially duplicate or related open PRs. + +Use the github-pr-search tool to search for PRs that might be addressing the same issue or feature. + +IMPORTANT: The input will contain a line `CURRENT_PR_NUMBER: NNNN`. This is the current PR number, you should not mark that the current PR as a duplicate of itself. + +Search using keywords from the PR title and description. Try multiple searches with different relevant terms. + +If you find potential duplicates: + +- List them with their titles and URLs +- Briefly explain why they might be related + +If no duplicates are found, say so clearly. BUT ONLY SAY "No duplicate PRs found" (don't say anything else if no dups) + +Keep your response concise and actionable. diff --git a/.opencode/agent/git-committer.md b/.opencode/agent/git-committer.md deleted file mode 100644 index 49c3e3de19f..00000000000 --- a/.opencode/agent/git-committer.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -description: Use this agent when you are asked to commit and push code changes to a git repository. -mode: subagent ---- - -You commit and push to git - -Commit messages should be brief since they are used to generate release notes. - -Messages should say WHY the change was made and not WHAT was changed. diff --git a/.opencode/agent/triage.md b/.opencode/agent/triage.md new file mode 100644 index 00000000000..5d1147a8859 --- /dev/null +++ b/.opencode/agent/triage.md @@ -0,0 +1,78 @@ +--- +mode: primary +hidden: true +model: opencode/claude-haiku-4-5 +color: "#44BA81" +tools: + "*": false + "github-triage": true +--- + +You are a triage agent responsible for triaging github issues. + +Use your github-triage tool to triage issues. + +## Labels + +### windows + +Use for any issue that mentions Windows (the OS). Be sure they are saying that they are on Windows. + +- Use if they mention WSL too + +#### perf + +Performance-related issues: + +- Slow performance +- High RAM usage +- High CPU usage + +**Only** add if it's likely a RAM or CPU issue. **Do not** add for LLM slowness. + +#### desktop + +Desktop app issues: + +- `opencode web` command +- The desktop app itself + +**Only** add if it's specifically about the Desktop application or `opencode web` view. **Do not** add for terminal, TUI, or general opencode issues. + +#### nix + +**Only** add if the issue explicitly mentions nix. + +#### zen + +**Only** add if the issue mentions "zen" or "opencode zen" or "opencode black". + +If the issue doesn't have "zen" or "opencode black" in it then don't add zen label + +#### docs + +Add if the issue requests better documentation or docs updates. + +#### opentui + +TUI issues potentially caused by our underlying TUI library: + +- Keybindings not working +- Scroll speed issues (too fast/slow/laggy) +- Screen flickering +- Crashes with opentui in the log + +**Do not** add for general TUI bugs. + +When assigning to people here are the following rules: + +adamdotdev: +ONLY assign adam if the issue will have the "desktop" label. + +fwang: +ONLY assign fwang if the issue will have the "zen" label. + +jayair: +ONLY assign jayair if the issue will have the "docs" label. + +In all other cases use best judgment. Avoid assigning to kommander needlessly, when in doubt assign to rekram1-node. diff --git a/.opencode/command/ai-deps.md b/.opencode/command/ai-deps.md new file mode 100644 index 00000000000..4d23c76a4d5 --- /dev/null +++ b/.opencode/command/ai-deps.md @@ -0,0 +1,24 @@ +--- +description: "Bump AI sdk dependencies minor / patch versions only" +--- + +Please read @package.json and @packages/opencode/package.json. + +Your job is to look into AI SDK dependencies, figure out if they have versions that can be upgraded (minor or patch versions ONLY no major ignore major changes). + +I want a report of every dependency and the version that can be upgraded to. +What would be even better is if you can give me links to the changelog for each dependency, or at least some reference info so I can see what bugs were fixed or new features were added. + +Consider using subagents for each dep to save your context window. + +Here is a short list of some deps (please be comprehensive tho): + +- "ai" +- "@ai-sdk/openai" +- "@ai-sdk/anthropic" +- "@openrouter/ai-sdk-provider" +- etc, etc + +DO NOT upgrade the dependencies yet, just make a list of all dependencies and their versions that can be upgraded to minor or patch versions only. + +Write up your findings to ai-sdk-updates.md diff --git a/.opencode/command/commit.md b/.opencode/command/commit.md new file mode 100644 index 00000000000..8e9346ebc88 --- /dev/null +++ b/.opencode/command/commit.md @@ -0,0 +1,28 @@ +--- +description: git commit and push +model: opencode/glm-4.6 +subtask: true +--- + +commit and push + +make sure it includes a prefix like +docs: +tui: +core: +ci: +ignore: +wip: + +For anything in the packages/web use the docs: prefix. + +For anything in the packages/app use the ignore: prefix. + +prefer to explain WHY something was done from an end user perspective instead of +WHAT was done. + +do not do generic messages like "improved agent experience" be very specific +about what user facing changes were made + +if there are changes do a git pull --rebase +if there are conflicts DO NOT FIX THEM. notify me and I will fix them diff --git a/.opencode/command/issues.md b/.opencode/command/issues.md new file mode 100644 index 00000000000..75b59616743 --- /dev/null +++ b/.opencode/command/issues.md @@ -0,0 +1,23 @@ +--- +description: "find issue(s) on github" +model: opencode/claude-haiku-4-5 +--- + +Search through existing issues in anomalyco/opencode using the gh cli to find issues matching this query: + +$ARGUMENTS + +Consider: + +1. Similar titles or descriptions +2. Same error messages or symptoms +3. Related functionality or components +4. Similar feature requests + +Please list any matching issues with: + +- Issue number and title +- Brief explanation of why it matches the query +- Link to the issue + +If no clear matches are found, say so. diff --git a/.opencode/command/rmslop.md b/.opencode/command/rmslop.md new file mode 100644 index 00000000000..02c9fc0844a --- /dev/null +++ b/.opencode/command/rmslop.md @@ -0,0 +1,15 @@ +--- +description: Remove AI code slop +--- + +Check the diff against dev, and remove all AI generated slop introduced in this branch. + +This includes: + +- Extra comments that a human wouldn't add or is inconsistent with the rest of the file +- Extra defensive checks or try/catch blocks that are abnormal for that area of the codebase (especially if called by trusted / validated codepaths) +- Casts to any to get around type issues +- Any other style that is inconsistent with the file +- Unnecessary emoji usage + +Report at the end with only a 1-3 sentence summary of what you changed diff --git a/.opencode/command/spellcheck.md b/.opencode/command/spellcheck.md new file mode 100644 index 00000000000..0abf23c4fd0 --- /dev/null +++ b/.opencode/command/spellcheck.md @@ -0,0 +1,5 @@ +--- +description: spellcheck all markdown file changes +--- + +Look at all the unstaged changes to markdown (.md, .mdx) files, pull out the lines that have changed, and check for spelling and grammar errors. diff --git a/.opencode/env.d.ts b/.opencode/env.d.ts new file mode 100644 index 00000000000..f2b13a934c4 --- /dev/null +++ b/.opencode/env.d.ts @@ -0,0 +1,4 @@ +declare module "*.txt" { + const content: string + export default content +} diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc new file mode 100644 index 00000000000..5d2dec625c6 --- /dev/null +++ b/.opencode/opencode.jsonc @@ -0,0 +1,23 @@ +{ + "$schema": "https://opencode.ai/config.json", + // "plugin": ["opencode-openai-codex-auth"], + // "enterprise": { + // "url": "https://enterprise.dev.opencode.ai", + // }, + "instructions": ["STYLE_GUIDE.md"], + "provider": { + "opencode": { + "options": {}, + }, + }, + "mcp": { + "context7": { + "type": "remote", + "url": "https://mcp.context7.com/mcp", + }, + }, + "tools": { + "github-triage": false, + "github-pr-search": false, + }, +} diff --git a/.opencode/skill/bun-file-io/SKILL.md b/.opencode/skill/bun-file-io/SKILL.md new file mode 100644 index 00000000000..ea39507d269 --- /dev/null +++ b/.opencode/skill/bun-file-io/SKILL.md @@ -0,0 +1,39 @@ +--- +name: bun-file-io +description: Use this when you are working on file operations like reading, writing, scanning, or deleting files. It summarizes the preferred file APIs and patterns used in this repo. It also notes when to use filesystem helpers for directories. +--- + +## Use this when + +- Editing file I/O or scans in `packages/opencode` +- Handling directory operations or external tools + +## Bun file APIs (from Bun docs) + +- `Bun.file(path)` is lazy; call `text`, `json`, `stream`, `arrayBuffer`, `bytes`, `exists` to read. +- Metadata: `file.size`, `file.type`, `file.name`. +- `Bun.write(dest, input)` writes strings, buffers, Blobs, Responses, or files. +- `Bun.file(...).delete()` deletes a file. +- `file.writer()` returns a FileSink for incremental writes. +- `Bun.Glob` + `Array.fromAsync(glob.scan({ cwd, absolute, onlyFiles, dot }))` for scans. +- Use `Bun.which` to find a binary, then `Bun.spawn` to run it. +- `Bun.readableStreamToText/Bytes/JSON` for stream output. + +## When to use node:fs + +- Use `node:fs/promises` for directories (`mkdir`, `readdir`, recursive operations). + +## Repo patterns + +- Prefer Bun APIs over Node `fs` for file access. +- Check `Bun.file(...).exists()` before reading. +- For binary/large files use `arrayBuffer()` and MIME checks via `file.type`. +- Use `Bun.Glob` + `Array.fromAsync` for scans. +- Decode tool stderr with `Bun.readableStreamToText`. +- For large writes, use `Bun.write(Bun.file(path), text)`. + +## Quick checklist + +- Use Bun APIs first. +- Use `path.join`/`path.resolve` for paths. +- Prefer promise `.catch(...)` over `try/catch` when possible. diff --git a/.opencode/themes/mytheme.json b/.opencode/themes/mytheme.json new file mode 100644 index 00000000000..e444de807c6 --- /dev/null +++ b/.opencode/themes/mytheme.json @@ -0,0 +1,223 @@ +{ + "$schema": "https://opencode.ai/theme.json", + "defs": { + "nord0": "#2E3440", + "nord1": "#3B4252", + "nord2": "#434C5E", + "nord3": "#4C566A", + "nord4": "#D8DEE9", + "nord5": "#E5E9F0", + "nord6": "#ECEFF4", + "nord7": "#8FBCBB", + "nord8": "#88C0D0", + "nord9": "#81A1C1", + "nord10": "#5E81AC", + "nord11": "#BF616A", + "nord12": "#D08770", + "nord13": "#EBCB8B", + "nord14": "#A3BE8C", + "nord15": "#B48EAD" + }, + "theme": { + "primary": { + "dark": "nord8", + "light": "nord10" + }, + "secondary": { + "dark": "nord9", + "light": "nord9" + }, + "accent": { + "dark": "nord7", + "light": "nord7" + }, + "error": { + "dark": "nord11", + "light": "nord11" + }, + "warning": { + "dark": "nord12", + "light": "nord12" + }, + "success": { + "dark": "nord14", + "light": "nord14" + }, + "info": { + "dark": "nord8", + "light": "nord10" + }, + "text": { + "dark": "nord4", + "light": "nord0" + }, + "textMuted": { + "dark": "nord3", + "light": "nord1" + }, + "background": { + "dark": "nord0", + "light": "nord6" + }, + "backgroundPanel": { + "dark": "nord1", + "light": "nord5" + }, + "backgroundElement": { + "dark": "nord1", + "light": "nord4" + }, + "border": { + "dark": "nord2", + "light": "nord3" + }, + "borderActive": { + "dark": "nord3", + "light": "nord2" + }, + "borderSubtle": { + "dark": "nord2", + "light": "nord3" + }, + "diffAdded": { + "dark": "nord14", + "light": "nord14" + }, + "diffRemoved": { + "dark": "nord11", + "light": "nord11" + }, + "diffContext": { + "dark": "nord3", + "light": "nord3" + }, + "diffHunkHeader": { + "dark": "nord3", + "light": "nord3" + }, + "diffHighlightAdded": { + "dark": "nord14", + "light": "nord14" + }, + "diffHighlightRemoved": { + "dark": "nord11", + "light": "nord11" + }, + "diffAddedBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "diffRemovedBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "diffContextBg": { + "dark": "nord1", + "light": "nord5" + }, + "diffLineNumber": { + "dark": "nord2", + "light": "nord4" + }, + "diffAddedLineNumberBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "diffRemovedLineNumberBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "markdownText": { + "dark": "nord4", + "light": "nord0" + }, + "markdownHeading": { + "dark": "nord8", + "light": "nord10" + }, + "markdownLink": { + "dark": "nord9", + "light": "nord9" + }, + "markdownLinkText": { + "dark": "nord7", + "light": "nord7" + }, + "markdownCode": { + "dark": "nord14", + "light": "nord14" + }, + "markdownBlockQuote": { + "dark": "nord3", + "light": "nord3" + }, + "markdownEmph": { + "dark": "nord12", + "light": "nord12" + }, + "markdownStrong": { + "dark": "nord13", + "light": "nord13" + }, + "markdownHorizontalRule": { + "dark": "nord3", + "light": "nord3" + }, + "markdownListItem": { + "dark": "nord8", + "light": "nord10" + }, + "markdownListEnumeration": { + "dark": "nord7", + "light": "nord7" + }, + "markdownImage": { + "dark": "nord9", + "light": "nord9" + }, + "markdownImageText": { + "dark": "nord7", + "light": "nord7" + }, + "markdownCodeBlock": { + "dark": "nord4", + "light": "nord0" + }, + "syntaxComment": { + "dark": "nord3", + "light": "nord3" + }, + "syntaxKeyword": { + "dark": "nord9", + "light": "nord9" + }, + "syntaxFunction": { + "dark": "nord8", + "light": "nord8" + }, + "syntaxVariable": { + "dark": "nord7", + "light": "nord7" + }, + "syntaxString": { + "dark": "nord14", + "light": "nord14" + }, + "syntaxNumber": { + "dark": "nord15", + "light": "nord15" + }, + "syntaxType": { + "dark": "nord7", + "light": "nord7" + }, + "syntaxOperator": { + "dark": "nord9", + "light": "nord9" + }, + "syntaxPunctuation": { + "dark": "nord4", + "light": "nord0" + } + } +} diff --git a/.opencode/tool/github-pr-search.ts b/.opencode/tool/github-pr-search.ts new file mode 100644 index 00000000000..587fdfaaf28 --- /dev/null +++ b/.opencode/tool/github-pr-search.ts @@ -0,0 +1,57 @@ +/// +import { tool } from "@opencode-ai/plugin" +import DESCRIPTION from "./github-pr-search.txt" + +async function githubFetch(endpoint: string, options: RequestInit = {}) { + const response = await fetch(`https://api.github.com${endpoint}`, { + ...options, + headers: { + Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, + Accept: "application/vnd.github+json", + "Content-Type": "application/json", + ...options.headers, + }, + }) + if (!response.ok) { + throw new Error(`GitHub API error: ${response.status} ${response.statusText}`) + } + return response.json() +} + +interface PR { + title: string + html_url: string +} + +export default tool({ + description: DESCRIPTION, + args: { + query: tool.schema.string().describe("Search query for PR titles and descriptions"), + limit: tool.schema.number().describe("Maximum number of results to return").default(10), + offset: tool.schema.number().describe("Number of results to skip for pagination").default(0), + }, + async execute(args) { + const owner = "anomalyco" + const repo = "opencode" + + const page = Math.floor(args.offset / args.limit) + 1 + const searchQuery = encodeURIComponent(`${args.query} repo:${owner}/${repo} type:pr state:open`) + const result = await githubFetch( + `/search/issues?q=${searchQuery}&per_page=${args.limit}&page=${page}&sort=updated&order=desc`, + ) + + if (result.total_count === 0) { + return `No PRs found matching "${args.query}"` + } + + const prs = result.items as PR[] + + if (prs.length === 0) { + return `No other PRs found matching "${args.query}"` + } + + const formatted = prs.map((pr) => `${pr.title}\n${pr.html_url}`).join("\n\n") + + return `Found ${result.total_count} PRs (showing ${prs.length}):\n\n${formatted}` + }, +}) diff --git a/.opencode/tool/github-pr-search.txt b/.opencode/tool/github-pr-search.txt new file mode 100644 index 00000000000..28d8643f13c --- /dev/null +++ b/.opencode/tool/github-pr-search.txt @@ -0,0 +1,10 @@ +Use this tool to search GitHub pull requests by title and description. + +This tool searches PRs in the sst/opencode repository and returns LLM-friendly results including: +- PR number and title +- Author +- State (open/closed/merged) +- Labels +- Description snippet + +Use the query parameter to search for keywords that might appear in PR titles or descriptions. diff --git a/.opencode/tool/github-triage.ts b/.opencode/tool/github-triage.ts new file mode 100644 index 00000000000..1e216f1c8da --- /dev/null +++ b/.opencode/tool/github-triage.ts @@ -0,0 +1,90 @@ +/// +// import { Octokit } from "@octokit/rest" +import { tool } from "@opencode-ai/plugin" +import DESCRIPTION from "./github-triage.txt" + +function getIssueNumber(): number { + const issue = parseInt(process.env.ISSUE_NUMBER ?? "", 10) + if (!issue) throw new Error("ISSUE_NUMBER env var not set") + return issue +} + +async function githubFetch(endpoint: string, options: RequestInit = {}) { + const response = await fetch(`https://api.github.com${endpoint}`, { + ...options, + headers: { + Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, + Accept: "application/vnd.github+json", + "Content-Type": "application/json", + ...options.headers, + }, + }) + if (!response.ok) { + throw new Error(`GitHub API error: ${response.status} ${response.statusText}`) + } + return response.json() +} + +export default tool({ + description: DESCRIPTION, + args: { + assignee: tool.schema + .enum(["thdxr", "adamdotdevin", "rekram1-node", "fwang", "jayair", "kommander"]) + .describe("The username of the assignee") + .default("rekram1-node"), + labels: tool.schema + .array(tool.schema.enum(["nix", "opentui", "perf", "desktop", "zen", "docs", "windows"])) + .describe("The labels(s) to add to the issue") + .default([]), + }, + async execute(args) { + const issue = getIssueNumber() + // const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }) + const owner = "anomalyco" + const repo = "opencode" + + const results: string[] = [] + + if (args.assignee === "adamdotdevin" && !args.labels.includes("desktop")) { + throw new Error("Only desktop issues should be assigned to adamdotdevin") + } + + if (args.assignee === "fwang" && !args.labels.includes("zen")) { + throw new Error("Only zen issues should be assigned to fwang") + } + + if (args.assignee === "kommander" && !args.labels.includes("opentui")) { + throw new Error("Only opentui issues should be assigned to kommander") + } + + // await octokit.rest.issues.addAssignees({ + // owner, + // repo, + // issue_number: issue, + // assignees: [args.assignee], + // }) + await githubFetch(`/repos/${owner}/${repo}/issues/${issue}/assignees`, { + method: "POST", + body: JSON.stringify({ assignees: [args.assignee] }), + }) + results.push(`Assigned @${args.assignee} to issue #${issue}`) + + const labels: string[] = args.labels.map((label) => (label === "desktop" ? "web" : label)) + + if (labels.length > 0) { + // await octokit.rest.issues.addLabels({ + // owner, + // repo, + // issue_number: issue, + // labels, + // }) + await githubFetch(`/repos/${owner}/${repo}/issues/${issue}/labels`, { + method: "POST", + body: JSON.stringify({ labels }), + }) + results.push(`Added labels: ${args.labels.join(", ")}`) + } + + return results.join("\n") + }, +}) diff --git a/.opencode/tool/github-triage.txt b/.opencode/tool/github-triage.txt new file mode 100644 index 00000000000..4c46a72c162 --- /dev/null +++ b/.opencode/tool/github-triage.txt @@ -0,0 +1,88 @@ +Use this tool to assign and/or label a Github issue. + +You can assign the following users: +- thdxr +- adamdotdevin +- fwang +- jayair +- kommander +- rekram1-node + + +You can use the following labels: +- nix +- opentui +- perf +- web +- zen +- docs + +Always try to assign an issue, if in doubt, assign rekram1-node to it. + +## Breakdown of responsibilities: + +### thdxr + +Dax is responsible for managing core parts of the application, for large feature requests, api changes, or things that require significant changes to the codebase assign him. + +This relates to OpenCode server primarily but has overlap with just about anything + +### adamdotdevin + +Adam is responsible for managing the Desktop/Web app. If there is an issue relating to the desktop app or `opencode web` command. Assign him. + + +### fwang + +Frank is responsible for managing Zen, if you see complaints about OpenCode Zen, maybe it's the dashboard, the model quality, billing issues, etc. Assign him to the issue. + +### jayair + +Jay is responsible for documentation. If there is an issue relating to documentation assign him. + +### kommander + +Sebastian is responsible for managing an OpenTUI (a library for building terminal user interfaces). OpenCode's TUI is built with OpenTUI. If there are issues about: +- random characters on screen +- keybinds not working on different terminals +- general terminal stuff +Then assign the issue to Him. + +### rekram1-node + +ALL BUGS SHOULD BE assigned to rekram1-node unless they have the `opentui` label. + +Assign Aiden to an issue as a catch all, if you can't assign anyone else. Most of the time this will be bugs/polish things. +If no one else makes sense to assign, assign rekram1-node to it. + +Always assign to aiden if the issue mentions "acp", "zed", or model performance issues + +## Breakdown of Labels: + +### nix + +Any issue that mentions nix, or nixos should have a nix label + +### opentui + +Anything relating to the TUI itself should have an opentui label + +### perf + +Anything related to slow performance, high ram, high cpu usage, or any other performance related issue should have a perf label + +### desktop + +Anything related to `opencode web` command or the desktop app should have a desktop label. Never add this label for anything terminal/tui related + +### zen + +Anything related to OpenCode Zen, billing, or model quality from Zen should have a zen label + +### docs + +Anything related to the documentation should have a docs label + +### windows + +Use for any issue that involves the windows OS diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..aa3a7ce2381 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +sst-env.d.ts \ No newline at end of file diff --git a/.vscode/launch.example.json b/.vscode/launch.example.json new file mode 100644 index 00000000000..3f8a2a76086 --- /dev/null +++ b/.vscode/launch.example.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "bun", + "request": "attach", + "name": "opencode (attach)", + "url": "ws://localhost:6499/" + } + ] +} diff --git a/.vscode/settings.example.json b/.vscode/settings.example.json new file mode 100644 index 00000000000..05bbf7fe11c --- /dev/null +++ b/.vscode/settings.example.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "oven.bun-vscode" + ] +} diff --git a/AGENTS.md b/AGENTS.md index cca69e4b666..3138f6c5ece 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,12 +1,4 @@ -## IMPORTANT - -- Try to keep things in one function unless composable or reusable -- DO NOT do unnecessary destructuring of variables -- DO NOT use `else` statements unless necessary -- DO NOT use `try`/`catch` if it can be avoided -- AVOID `try`/`catch` where possible -- AVOID `else` statements -- AVOID using `any` type -- AVOID `let` statements -- PREFER single word variable names where possible -- Use as many bun apis as possible like Bun.file() +- To test opencode in `packages/opencode`, run `bun dev`. +- To regenerate the JavaScript SDK, run `./packages/sdk/js/script/build.ts`. +- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. +- The default branch in this repo is `dev`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..a32504b22f8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,260 @@ +# Contributing to OpenCode + +We want to make it easy for you to contribute to OpenCode. Here are the most common type of changes that get merged: + +- Bug fixes +- Additional LSPs / Formatters +- Improvements to LLM performance +- Support for new providers +- Fixes for environment-specific quirks +- Missing standard behavior +- Documentation improvements + +However, any UI or core product feature must go through a design review with the core team before implementation. + +If you are unsure if a PR would be accepted, feel free to ask a maintainer or look for issues with any of the following labels: + +- [`help wanted`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Ahelp-wanted) +- [`good first issue`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) +- [`bug`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) +- [`perf`](https://github.com/anomalyco/opencode/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22perf%22) + +> [!NOTE] +> PRs that ignore these guardrails will likely be closed. + +Want to take on an issue? Leave a comment and a maintainer may assign it to you unless it is something we are already working on. + +## Developing OpenCode + +- Requirements: Bun 1.3+ +- Install dependencies and start the dev server from the repo root: + + ```bash + bun install + bun dev + ``` + +### Running against a different directory + +By default, `bun dev` runs OpenCode in the `packages/opencode` directory. To run it against a different directory or repository: + +```bash +bun dev +``` + +To run OpenCode in the root of the opencode repo itself: + +```bash +bun dev . +``` + +### Building a "localcode" + +To compile a standalone executable: + +```bash +./packages/opencode/script/build.ts --single +``` + +Then run it with: + +```bash +./packages/opencode/dist/opencode-/bin/opencode +``` + +Replace `` with your platform (e.g., `darwin-arm64`, `linux-x64`). + +- Core pieces: + - `packages/opencode`: OpenCode core business logic & server. + - `packages/opencode/src/cli/cmd/tui/`: The TUI code, written in SolidJS with [opentui](https://github.com/sst/opentui) + - `packages/app`: The shared web UI components, written in SolidJS + - `packages/desktop`: The native desktop app, built with Tauri (wraps `packages/app`) + - `packages/plugin`: Source for `@opencode-ai/plugin` + +### Understanding bun dev vs opencode + +During development, `bun dev` is the local equivalent of the built `opencode` command. Both run the same CLI interface: + +```bash +# Development (from project root) +bun dev --help # Show all available commands +bun dev serve # Start headless API server +bun dev web # Start server + open web interface +bun dev # Start TUI in specific directory + +# Production +opencode --help # Show all available commands +opencode serve # Start headless API server +opencode web # Start server + open web interface +opencode # Start TUI in specific directory +``` + +### Running the API Server + +To start the OpenCode headless API server: + +```bash +bun dev serve +``` + +This starts the headless server on port 4096 by default. You can specify a different port: + +```bash +bun dev serve --port 8080 +``` + +### Running the Web App + +To test UI changes during development: + +1. **First, start the OpenCode server** (see [Running the API Server](#running-the-api-server) section above) +2. **Then run the web app:** + +```bash +bun run --cwd packages/app dev +``` + +This starts a local dev server at http://localhost:5173 (or similar port shown in output). Most UI changes can be tested here, but the server must be running for full functionality. + +### Running the Desktop App + +The desktop app is a native Tauri application that wraps the web UI. + +To run the native desktop app: + +```bash +bun run --cwd packages/desktop tauri dev +``` + +This starts the web dev server on http://localhost:1420 and opens the native window. + +If you only want the web dev server (no native shell): + +```bash +bun run --cwd packages/desktop dev +``` + +To create a production `dist/` and build the native app bundle: + +```bash +bun run --cwd packages/desktop tauri build +``` + +This runs `bun run --cwd packages/desktop build` automatically via Tauri’s `beforeBuildCommand`. + +> [!NOTE] +> Running the desktop app requires additional Tauri dependencies (Rust toolchain, platform-specific libraries). See the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for setup instructions. + +> [!NOTE] +> If you make changes to the API or SDK (e.g. `packages/opencode/src/server/server.ts`), run `./script/generate.ts` to regenerate the SDK and related files. + +Please try to follow the [style guide](./STYLE_GUIDE.md) + +### Setting up a Debugger + +Bun debugging is currently rough around the edges. We hope this guide helps you get set up and avoid some pain points. + +The most reliable way to debug OpenCode is to run it manually in a terminal via `bun run --inspect= dev ...` and attach +your debugger via that URL. Other methods can result in breakpoints being mapped incorrectly, at least in VSCode (YMMV). + +Caveats: + +- If you want to run the OpenCode TUI and have breakpoints triggered in the server code, you might need to run `bun dev spawn` instead of + the usual `bun dev`. This is because `bun dev` runs the server in a worker thread and breakpoints might not work there. +- If `spawn` does not work for you, you can debug the server separately: + - Debug server: `bun run --inspect=ws://localhost:6499/ --cwd packages/opencode ./src/index.ts serve --port 4096`, + then attach TUI with `opencode attach http://localhost:4096` + - Debug TUI: `bun run --inspect=ws://localhost:6499/ --cwd packages/opencode --conditions=browser ./src/index.ts` + +Other tips and tricks: + +- You might want to use `--inspect-wait` or `--inspect-brk` instead of `--inspect`, depending on your workflow +- Specifying `--inspect=ws://localhost:6499/` on every invocation can be tiresome, you may want to `export BUN_OPTIONS=--inspect=ws://localhost:6499/` instead + +#### VSCode Setup + +If you use VSCode, you can use our example configurations [.vscode/settings.example.json](.vscode/settings.example.json) and [.vscode/launch.example.json](.vscode/launch.example.json). + +Some debug methods that can be problematic: + +- Debug configurations with `"request": "launch"` can have breakpoints incorrectly mapped and thus unusable +- The same problem arises when running OpenCode in the VSCode `JavaScript Debug Terminal` + +With that said, you may want to try these methods, as they might work for you. + +## Pull Request Expectations + +### Issue First Policy + +**All PRs must reference an existing issue.** Before opening a PR, open an issue describing the bug or feature. This helps maintainers triage and prevents duplicate work. PRs without a linked issue may be closed without review. + +- Use `Fixes #123` or `Closes #123` in your PR description to link the issue +- For small fixes, a brief issue is fine - just enough context for maintainers to understand the problem + +### General Requirements + +- Keep pull requests small and focused +- Explain the issue and why your change fixes it +- Before adding new functionality, ensure it doesn't already exist elsewhere in the codebase + +### UI Changes + +If your PR includes UI changes, please include screenshots or videos showing the before and after. This helps maintainers review faster and gives you quicker feedback. + +### Logic Changes + +For non-UI changes (bug fixes, new features, refactors), explain **how you verified it works**: + +- What did you test? +- How can a reviewer reproduce/confirm the fix? + +### No AI-Generated Walls of Text + +Long, AI-generated PR descriptions and issues are not acceptable and may be ignored. Respect the maintainers' time: + +- Write short, focused descriptions +- Explain what changed and why in your own words +- If you can't explain it briefly, your PR might be too large + +### PR Titles + +PR titles should follow conventional commit standards: + +- `feat:` new feature or functionality +- `fix:` bug fix +- `docs:` documentation or README changes +- `chore:` maintenance tasks, dependency updates, etc. +- `refactor:` code refactoring without changing behavior +- `test:` adding or updating tests + +You can optionally include a scope to indicate which package is affected: + +- `feat(app):` feature in the app package +- `fix(desktop):` bug fix in the desktop package +- `chore(opencode):` maintenance in the opencode package + +Examples: + +- `docs: update contributing guidelines` +- `fix: resolve crash on startup` +- `feat: add dark mode support` +- `feat(app): add dark mode support` +- `fix(desktop): resolve crash on startup` +- `chore: bump dependency versions` + +### Style Preferences + +These are not strictly enforced, they are just general guidelines: + +- **Functions:** Keep logic within a single function unless breaking it out adds clear reuse or composition benefits. +- **Destructuring:** Do not do unnecessary destructuring of variables. +- **Control flow:** Avoid `else` statements. +- **Error handling:** Prefer `.catch(...)` instead of `try`/`catch` when possible. +- **Types:** Reach for precise types and avoid `any`. +- **Variables:** Stick to immutable patterns and avoid `let`. +- **Naming:** Choose concise single-word identifiers when they remain descriptive. +- **Runtime APIs:** Use Bun helpers such as `Bun.file()` when they fit the use case. + +## Feature Requests + +For net-new functionality, start with a design conversation. Open an issue describing the problem, your proposed approach (optional), and why it belongs in OpenCode. The core team will help decide whether it should move forward; please wait for that approval instead of opening a feature PR directly. diff --git a/README.md b/README.md index 1e16bde8cc5..64ca1ef7a6f 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@

- - - opencode logo + + + OpenCode logo

-

AI coding agent, built for the terminal.

+

The open source AI coding agent.

Discord npm - Build status + Build status

-[![opencode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) +[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) --- @@ -26,13 +26,36 @@ curl -fsSL https://opencode.ai/install | bash # Package managers npm i -g opencode-ai@latest # or bun/pnpm/yarn -brew install sst/tap/opencode # macOS and Linux +scoop install opencode # Windows +choco install opencode # Windows +brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date) +brew install opencode # macOS and Linux (official brew formula, updated less) paru -S opencode-bin # Arch Linux +mise use -g opencode # Any OS +nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch ``` > [!TIP] > Remove versions older than 0.1.x before installing. +### Desktop App (BETA) + +OpenCode is also available as a desktop application. Download directly from the [releases page](https://github.com/anomalyco/opencode/releases) or [opencode.ai/download](https://opencode.ai/download). + +| Platform | Download | +| --------------------- | ------------------------------------- | +| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | +| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | +| Windows | `opencode-desktop-windows-x64.exe` | +| Linux | `.deb`, `.rpm`, or AppImage | + +```bash +# macOS (Homebrew) +brew install --cask opencode-desktop +# Windows (Scoop) +scoop bucket add extras; scoop install extras/opencode-desktop +``` + #### Installation Directory The install script respects the following priority order for the installation path: @@ -48,63 +71,45 @@ OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bas XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash ``` -### Documentation - -For more info on how to configure opencode [**head over to our docs**](https://opencode.ai/docs). - -### Contributing +### Agents -opencode is an opinionated tool so any fundamental feature needs to go through a -design process with the core team. +OpenCode includes two built-in agents you can switch between with the `Tab` key. -> [!IMPORTANT] -> We do not accept PRs for core features. +- **build** - Default, full access agent for development work +- **plan** - Read-only agent for analysis and code exploration + - Denies file edits by default + - Asks permission before running bash commands + - Ideal for exploring unfamiliar codebases or planning changes -However we still merge a ton of PRs - you can contribute: +Also, included is a **general** subagent for complex searches and multistep tasks. +This is used internally and can be invoked using `@general` in messages. -- Bug fixes -- Improvements to LLM performance -- Support for new providers -- Fixes for env specific quirks -- Missing standard behavior -- Documentation +Learn more about [agents](https://opencode.ai/docs/agents). -Take a look at the git history to see what kind of PRs we end up merging. +### Documentation -> [!NOTE] -> If you do not follow the above guidelines we might close your PR. +For more info on how to configure OpenCode [**head over to our docs**](https://opencode.ai/docs). -To run opencode locally you need. +### Contributing -- Bun -- Golang 1.24.x +If you're interested in contributing to OpenCode, please read our [contributing docs](./CONTRIBUTING.md) before submitting a pull request. -And run. +### Building on OpenCode -```bash -$ bun install -$ bun dev -``` - -#### Development Notes - -**API Client**: After making changes to the TypeScript API endpoints in `packages/opencode/src/server/server.ts`, you will need the opencode team to generate a new stainless sdk for the clients. +If you are working on a project that's related to OpenCode and is using "opencode" as a part of its name; for example, "opencode-dashboard" or "opencode-mobile", please add a note to your README to clarify that it is not built by the OpenCode team and is not affiliated with us in any way. ### FAQ -#### How is this different than Claude Code? +#### How is this different from Claude Code? It's very similar to Claude Code in terms of capability. Here are the key differences: - 100% open source -- Not coupled to any provider. Although Anthropic is recommended, opencode can be used with OpenAI, Google or even local models. As models evolve the gaps between them will close and pricing will drop so being provider-agnostic is important. -- A focus on TUI. opencode is built by neovim users and the creators of [terminal.shop](https://terminal.shop); we are going to push the limits of what's possible in the terminal. -- A client/server architecture. This for example can allow opencode to run on your computer, while you can drive it remotely from a mobile app. Meaning that the TUI frontend is just one of the possible clients. - -#### What's the other repo? - -The other confusingly named repo has no relation to this one. You can [read the story behind it here](https://x.com/thdxr/status/1933561254481666466). +- Not coupled to any provider. Although we recommend the models we provide through [OpenCode Zen](https://opencode.ai/zen); OpenCode can be used with Claude, OpenAI, Google or even local models. As models evolve the gaps between them will close and pricing will drop so being provider-agnostic is important. +- Out of the box LSP support +- A focus on TUI. OpenCode is built by neovim users and the creators of [terminal.shop](https://terminal.shop); we are going to push the limits of what's possible in the terminal. +- A client/server architecture. This for example can allow OpenCode to run on your computer, while you can drive it remotely from a mobile app. Meaning that the TUI frontend is just one of the possible clients. --- -**Join our community** [Discord](https://discord.gg/opencode) | [YouTube](https://www.youtube.com/c/sst-dev) | [X.com](https://x.com/SST_dev) +**Join our community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 00000000000..4b56e0fb0b0 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,118 @@ +

+ + + + + OpenCode logo + + +

+

开源的 AI Coding Agent。

+

+ Discord + npm + Build status +

+ +[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) + +--- + +### 安装 + +```bash +# 直接安装 (YOLO) +curl -fsSL https://opencode.ai/install | bash + +# 软件包管理器 +npm i -g opencode-ai@latest # 也可使用 bun/pnpm/yarn +scoop install opencode # Windows +choco install opencode # Windows +brew install anomalyco/tap/opencode # macOS 和 Linux(推荐,始终保持最新) +brew install opencode # macOS 和 Linux(官方 brew formula,更新频率较低) +paru -S opencode-bin # Arch Linux +mise use -g opencode # 任意系统 +nix run nixpkgs#opencode # 或用 github:anomalyco/opencode 获取最新 dev 分支 +``` + +> [!TIP] +> 安装前请先移除 0.1.x 之前的旧版本。 + +### 桌面应用程序 (BETA) + +OpenCode 也提供桌面版应用。可直接从 [发布页 (releases page)](https://github.com/anomalyco/opencode/releases) 或 [opencode.ai/download](https://opencode.ai/download) 下载。 + +| 平台 | 下载文件 | +| --------------------- | ------------------------------------- | +| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | +| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | +| Windows | `opencode-desktop-windows-x64.exe` | +| Linux | `.deb`、`.rpm` 或 AppImage | + +```bash +# macOS (Homebrew Cask) +brew install --cask opencode-desktop +# Windows (Scoop) +scoop bucket add extras; scoop install extras/opencode-desktop +``` + +#### 安装目录 + +安装脚本按照以下优先级决定安装路径: + +1. `$OPENCODE_INSTALL_DIR` - 自定义安装目录 +2. `$XDG_BIN_DIR` - 符合 XDG 基础目录规范的路径 +3. `$HOME/bin` - 如果存在或可创建的用户二进制目录 +4. `$HOME/.opencode/bin` - 默认备用路径 + +```bash +# 示例 +OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash +XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash +``` + +### Agents + +OpenCode 内置两种 Agent,可用 `Tab` 键快速切换: + +- **build** - 默认模式,具备完整权限,适合开发工作 +- **plan** - 只读模式,适合代码分析与探索 + - 默认拒绝修改文件 + - 运行 bash 命令前会询问 + - 便于探索未知代码库或规划改动 + +另外还包含一个 **general** 子 Agent,用于复杂搜索和多步任务,内部使用,也可在消息中输入 `@general` 调用。 + +了解更多 [Agents](https://opencode.ai/docs/agents) 相关信息。 + +### 文档 + +更多配置说明请查看我们的 [**官方文档**](https://opencode.ai/docs)。 + +### 参与贡献 + +如有兴趣贡献代码,请在提交 PR 前阅读 [贡献指南 (Contributing Docs)](./CONTRIBUTING.md)。 + +### 基于 OpenCode 进行开发 + +如果你在项目名中使用了 “opencode”(如 “opencode-dashboard” 或 “opencode-mobile”),请在 README 里注明该项目不是 OpenCode 团队官方开发,且不存在隶属关系。 + +### 常见问题 (FAQ) + +#### 这和 Claude Code 有什么不同? + +功能上很相似,关键差异: + +- 100% 开源。 +- 不绑定特定提供商。推荐使用 [OpenCode Zen](https://opencode.ai/zen) 的模型,但也可搭配 Claude、OpenAI、Google 甚至本地模型。模型迭代会缩小差异、降低成本,因此保持 provider-agnostic 很重要。 +- 内置 LSP 支持。 +- 聚焦终端界面 (TUI)。OpenCode 由 Neovim 爱好者和 [terminal.shop](https://terminal.shop) 的创建者打造,会持续探索终端的极限。 +- 客户端/服务器架构。可在本机运行,同时用移动设备远程驱动。TUI 只是众多潜在客户端之一。 + +#### 另一个同名的仓库是什么? + +另一个名字相近的仓库与本项目无关。[点击这里了解背后故事](https://x.com/thdxr/status/1933561254481666466)。 + +--- + +**加入我们的社区** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/README.zh-TW.md b/README.zh-TW.md new file mode 100644 index 00000000000..66664a70305 --- /dev/null +++ b/README.zh-TW.md @@ -0,0 +1,118 @@ +

+ + + + + OpenCode logo + + +

+

開源的 AI Coding Agent。

+

+ Discord + npm + Build status +

+ +[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) + +--- + +### 安裝 + +```bash +# 直接安裝 (YOLO) +curl -fsSL https://opencode.ai/install | bash + +# 套件管理員 +npm i -g opencode-ai@latest # 也可使用 bun/pnpm/yarn +scoop install opencode # Windows +choco install opencode # Windows +brew install anomalyco/tap/opencode # macOS 與 Linux(推薦,始終保持最新) +brew install opencode # macOS 與 Linux(官方 brew formula,更新頻率較低) +paru -S opencode-bin # Arch Linux +mise use -g github:anomalyco/opencode # 任何作業系統 +nix run nixpkgs#opencode # 或使用 github:anomalyco/opencode 以取得最新開發分支 +``` + +> [!TIP] +> 安裝前請先移除 0.1.x 以前的舊版本。 + +### 桌面應用程式 (BETA) + +OpenCode 也提供桌面版應用程式。您可以直接從 [發佈頁面 (releases page)](https://github.com/anomalyco/opencode/releases) 或 [opencode.ai/download](https://opencode.ai/download) 下載。 + +| 平台 | 下載連結 | +| --------------------- | ------------------------------------- | +| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | +| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | +| Windows | `opencode-desktop-windows-x64.exe` | +| Linux | `.deb`, `.rpm`, 或 AppImage | + +```bash +# macOS (Homebrew Cask) +brew install --cask opencode-desktop +# Windows (Scoop) +scoop bucket add extras; scoop install extras/opencode-desktop +``` + +#### 安裝目錄 + +安裝腳本會依據以下優先順序決定安裝路徑: + +1. `$OPENCODE_INSTALL_DIR` - 自定義安裝目錄 +2. `$XDG_BIN_DIR` - 符合 XDG 基礎目錄規範的路徑 +3. `$HOME/bin` - 標準使用者執行檔目錄 (若存在或可建立) +4. `$HOME/.opencode/bin` - 預設備用路徑 + +```bash +# 範例 +OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash +XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash +``` + +### Agents + +OpenCode 內建了兩種 Agent,您可以使用 `Tab` 鍵快速切換。 + +- **build** - 預設模式,具備完整權限的 Agent,適用於開發工作。 +- **plan** - 唯讀模式,適用於程式碼分析與探索。 + - 預設禁止修改檔案。 + - 執行 bash 指令前會詢問權限。 + - 非常適合用來探索陌生的程式碼庫或規劃變更。 + +此外,OpenCode 還包含一個 **general** 子 Agent,用於處理複雜搜尋與多步驟任務。此 Agent 供系統內部使用,亦可透過在訊息中輸入 `@general` 來呼叫。 + +了解更多關於 [Agents](https://opencode.ai/docs/agents) 的資訊。 + +### 線上文件 + +關於如何設定 OpenCode 的詳細資訊,請參閱我們的 [**官方文件**](https://opencode.ai/docs)。 + +### 參與貢獻 + +如果您有興趣參與 OpenCode 的開發,請在提交 Pull Request 前先閱讀我們的 [貢獻指南 (Contributing Docs)](./CONTRIBUTING.md)。 + +### 基於 OpenCode 進行開發 + +如果您正在開發與 OpenCode 相關的專案,並在名稱中使用了 "opencode"(例如 "opencode-dashboard" 或 "opencode-mobile"),請在您的 README 中加入聲明,說明該專案並非由 OpenCode 團隊開發,且與我們沒有任何隸屬關係。 + +### 常見問題 (FAQ) + +#### 這跟 Claude Code 有什麼不同? + +在功能面上與 Claude Code 非常相似。以下是關鍵差異: + +- 100% 開源。 +- 不綁定特定的服務提供商。雖然我們推薦使用透過 [OpenCode Zen](https://opencode.ai/zen) 提供的模型,但 OpenCode 也可搭配 Claude, OpenAI, Google 甚至本地模型使用。隨著模型不斷演進,彼此間的差距會縮小且價格會下降,因此具備「不限廠商 (provider-agnostic)」的特性至關重要。 +- 內建 LSP (語言伺服器協定) 支援。 +- 專注於終端機介面 (TUI)。OpenCode 由 Neovim 愛好者與 [terminal.shop](https://terminal.shop) 的創作者打造;我們將不斷挑戰終端機介面的極限。 +- 客戶端/伺服器架構 (Client/Server Architecture)。這讓 OpenCode 能夠在您的電腦上運行的同時,由行動裝置進行遠端操控。這意味著 TUI 前端只是眾多可能的客戶端之一。 + +#### 另一個同名的 Repo 是什麼? + +另一個名稱相近的儲存庫與本專案無關。您可以點此[閱讀背後的故事](https://x.com/thdxr/status/1933561254481666466)。 + +--- + +**加入我們的社群** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..93c7341cef6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ +# Security + +## Threat Model + +### Overview + +OpenCode is an AI-powered coding assistant that runs locally on your machine. It provides an agent system with access to powerful tools including shell execution, file operations, and web access. + +### No Sandbox + +OpenCode does **not** sandbox the agent. The permission system exists as a UX feature to help users stay aware of what actions the agent is taking - it prompts for confirmation before executing commands, writing files, etc. However, it is not designed to provide security isolation. + +If you need true isolation, run OpenCode inside a Docker container or VM. + +### Server Mode + +Server mode is opt-in only. When enabled, set `OPENCODE_SERVER_PASSWORD` to require HTTP Basic Auth. Without this, the server runs unauthenticated (with a warning). It is the end user's responsibility to secure the server - any functionality it provides is not a vulnerability. + +### Out of Scope + +| Category | Rationale | +| ------------------------------- | ----------------------------------------------------------------------- | +| **Server access when opted-in** | If you enable server mode, API access is expected behavior | +| **Sandbox escapes** | The permission system is not a sandbox (see above) | +| **LLM provider data handling** | Data sent to your configured LLM provider is governed by their policies | +| **MCP server behavior** | External MCP servers you configure are outside our trust boundary | +| **Malicious config files** | Users control their own config; modifying it is not an attack vector | + +--- + +# Reporting Security Issues + +We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. + +To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/anomalyco/opencode/security/advisories/new) tab. + +The team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. + +## Escalation + +If you do not receive an acknowledgement of your report within 6 business days, you may send an email to security@anoma.ly diff --git a/STATS.md b/STATS.md index 1ab99f92028..5cfa76f16db 100644 --- a/STATS.md +++ b/STATS.md @@ -1,57 +1,210 @@ # Download Stats -| Date | GitHub Downloads | npm Downloads | Total | -| ---------- | ---------------- | ---------------- | ----------------- | -| 2025-06-29 | 18,789 (+0) | 39,420 (+0) | 58,209 (+0) | -| 2025-06-30 | 20,127 (+1,338) | 41,059 (+1,639) | 61,186 (+2,977) | -| 2025-07-01 | 22,108 (+1,981) | 43,745 (+2,686) | 65,853 (+4,667) | -| 2025-07-02 | 24,814 (+2,706) | 46,168 (+2,423) | 70,982 (+5,129) | -| 2025-07-03 | 27,834 (+3,020) | 49,955 (+3,787) | 77,789 (+6,807) | -| 2025-07-04 | 30,608 (+2,774) | 54,758 (+4,803) | 85,366 (+7,577) | -| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) | -| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) | -| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) | -| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) | -| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) | -| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) | -| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) | -| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) | -| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) | -| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) | -| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) | -| 2025-07-17 | 66,684 (+4,371) | 100,048 (+4,790) | 166,732 (+9,161) | -| 2025-07-18 | 70,379 (+3,695) | 102,587 (+2,539) | 172,966 (+6,234) | -| 2025-07-19 | 73,497 (+3,117) | 105,904 (+3,317) | 179,401 (+6,434) | -| 2025-07-20 | 76,453 (+2,956) | 109,044 (+3,140) | 185,497 (+6,096) | -| 2025-07-21 | 80,197 (+3,744) | 113,537 (+4,493) | 193,734 (+8,237) | -| 2025-07-22 | 84,251 (+4,054) | 118,073 (+4,536) | 202,324 (+8,590) | -| 2025-07-23 | 88,589 (+4,338) | 121,436 (+3,363) | 210,025 (+7,701) | -| 2025-07-24 | 92,469 (+3,880) | 124,091 (+2,655) | 216,560 (+6,535) | -| 2025-07-25 | 96,417 (+3,948) | 126,985 (+2,894) | 223,402 (+6,842) | -| 2025-07-26 | 100,646 (+4,229) | 131,411 (+4,426) | 232,057 (+8,655) | -| 2025-07-27 | 102,644 (+1,998) | 134,736 (+3,325) | 237,380 (+5,323) | -| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) | -| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) | -| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) | -| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) | -| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) | -| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) | -| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) | -| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) | -| 2025-08-05 | 141,596 (+5,330) | 155,752 (+2,492) | 297,348 (+7,822) | -| 2025-08-06 | 147,067 (+5,471) | 158,309 (+2,557) | 305,376 (+8,028) | -| 2025-08-07 | 152,591 (+5,524) | 160,889 (+2,580) | 313,480 (+8,104) | -| 2025-08-08 | 158,187 (+5,596) | 163,448 (+2,559) | 321,635 (+8,155) | -| 2025-08-09 | 162,770 (+4,583) | 165,721 (+2,273) | 328,491 (+6,856) | -| 2025-08-10 | 165,695 (+2,925) | 167,109 (+1,388) | 332,804 (+4,313) | -| 2025-08-11 | 169,297 (+3,602) | 167,953 (+844) | 337,250 (+4,446) | -| 2025-08-12 | 176,307 (+7,010) | 171,876 (+3,923) | 348,183 (+10,933) | -| 2025-08-13 | 182,997 (+6,690) | 177,182 (+5,306) | 360,179 (+11,996) | -| 2025-08-14 | 189,063 (+6,066) | 179,741 (+2,559) | 368,804 (+8,625) | -| 2025-08-15 | 193,608 (+4,545) | 181,792 (+2,051) | 375,400 (+6,596) | -| 2025-08-16 | 198,118 (+4,510) | 184,558 (+2,766) | 382,676 (+7,276) | -| 2025-08-17 | 201,299 (+3,181) | 186,269 (+1,711) | 387,568 (+4,892) | -| 2025-08-18 | 204,559 (+3,260) | 187,399 (+1,130) | 391,958 (+4,390) | -| 2025-08-19 | 209,814 (+5,255) | 189,668 (+2,269) | 399,482 (+7,524) | -| 2025-08-20 | 214,497 (+4,683) | 191,481 (+1,813) | 405,978 (+6,496) | -| 2025-08-21 | 220,465 (+5,968) | 194,784 (+3,303) | 415,249 (+9,271) | +| Date | GitHub Downloads | npm Downloads | Total | +| ---------- | -------------------- | -------------------- | -------------------- | +| 2025-06-29 | 18,789 (+0) | 39,420 (+0) | 58,209 (+0) | +| 2025-06-30 | 20,127 (+1,338) | 41,059 (+1,639) | 61,186 (+2,977) | +| 2025-07-01 | 22,108 (+1,981) | 43,745 (+2,686) | 65,853 (+4,667) | +| 2025-07-02 | 24,814 (+2,706) | 46,168 (+2,423) | 70,982 (+5,129) | +| 2025-07-03 | 27,834 (+3,020) | 49,955 (+3,787) | 77,789 (+6,807) | +| 2025-07-04 | 30,608 (+2,774) | 54,758 (+4,803) | 85,366 (+7,577) | +| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) | +| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) | +| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) | +| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) | +| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) | +| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) | +| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) | +| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) | +| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) | +| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) | +| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) | +| 2025-07-17 | 66,684 (+4,371) | 100,048 (+4,790) | 166,732 (+9,161) | +| 2025-07-18 | 70,379 (+3,695) | 102,587 (+2,539) | 172,966 (+6,234) | +| 2025-07-19 | 73,497 (+3,117) | 105,904 (+3,317) | 179,401 (+6,434) | +| 2025-07-20 | 76,453 (+2,956) | 109,044 (+3,140) | 185,497 (+6,096) | +| 2025-07-21 | 80,197 (+3,744) | 113,537 (+4,493) | 193,734 (+8,237) | +| 2025-07-22 | 84,251 (+4,054) | 118,073 (+4,536) | 202,324 (+8,590) | +| 2025-07-23 | 88,589 (+4,338) | 121,436 (+3,363) | 210,025 (+7,701) | +| 2025-07-24 | 92,469 (+3,880) | 124,091 (+2,655) | 216,560 (+6,535) | +| 2025-07-25 | 96,417 (+3,948) | 126,985 (+2,894) | 223,402 (+6,842) | +| 2025-07-26 | 100,646 (+4,229) | 131,411 (+4,426) | 232,057 (+8,655) | +| 2025-07-27 | 102,644 (+1,998) | 134,736 (+3,325) | 237,380 (+5,323) | +| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) | +| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) | +| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) | +| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) | +| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) | +| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) | +| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) | +| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) | +| 2025-08-05 | 141,596 (+5,330) | 155,752 (+2,492) | 297,348 (+7,822) | +| 2025-08-06 | 147,067 (+5,471) | 158,309 (+2,557) | 305,376 (+8,028) | +| 2025-08-07 | 152,591 (+5,524) | 160,889 (+2,580) | 313,480 (+8,104) | +| 2025-08-08 | 158,187 (+5,596) | 163,448 (+2,559) | 321,635 (+8,155) | +| 2025-08-09 | 162,770 (+4,583) | 165,721 (+2,273) | 328,491 (+6,856) | +| 2025-08-10 | 165,695 (+2,925) | 167,109 (+1,388) | 332,804 (+4,313) | +| 2025-08-11 | 169,297 (+3,602) | 167,953 (+844) | 337,250 (+4,446) | +| 2025-08-12 | 176,307 (+7,010) | 171,876 (+3,923) | 348,183 (+10,933) | +| 2025-08-13 | 182,997 (+6,690) | 177,182 (+5,306) | 360,179 (+11,996) | +| 2025-08-14 | 189,063 (+6,066) | 179,741 (+2,559) | 368,804 (+8,625) | +| 2025-08-15 | 193,608 (+4,545) | 181,792 (+2,051) | 375,400 (+6,596) | +| 2025-08-16 | 198,118 (+4,510) | 184,558 (+2,766) | 382,676 (+7,276) | +| 2025-08-17 | 201,299 (+3,181) | 186,269 (+1,711) | 387,568 (+4,892) | +| 2025-08-18 | 204,559 (+3,260) | 187,399 (+1,130) | 391,958 (+4,390) | +| 2025-08-19 | 209,814 (+5,255) | 189,668 (+2,269) | 399,482 (+7,524) | +| 2025-08-20 | 214,497 (+4,683) | 191,481 (+1,813) | 405,978 (+6,496) | +| 2025-08-21 | 220,465 (+5,968) | 194,784 (+3,303) | 415,249 (+9,271) | +| 2025-08-22 | 225,899 (+5,434) | 197,204 (+2,420) | 423,103 (+7,854) | +| 2025-08-23 | 229,005 (+3,106) | 199,238 (+2,034) | 428,243 (+5,140) | +| 2025-08-24 | 232,098 (+3,093) | 201,157 (+1,919) | 433,255 (+5,012) | +| 2025-08-25 | 236,607 (+4,509) | 202,650 (+1,493) | 439,257 (+6,002) | +| 2025-08-26 | 242,783 (+6,176) | 205,242 (+2,592) | 448,025 (+8,768) | +| 2025-08-27 | 248,409 (+5,626) | 205,242 (+0) | 453,651 (+5,626) | +| 2025-08-28 | 252,796 (+4,387) | 205,242 (+0) | 458,038 (+4,387) | +| 2025-08-29 | 256,045 (+3,249) | 211,075 (+5,833) | 467,120 (+9,082) | +| 2025-08-30 | 258,863 (+2,818) | 212,397 (+1,322) | 471,260 (+4,140) | +| 2025-08-31 | 262,004 (+3,141) | 213,944 (+1,547) | 475,948 (+4,688) | +| 2025-09-01 | 265,359 (+3,355) | 215,115 (+1,171) | 480,474 (+4,526) | +| 2025-09-02 | 270,483 (+5,124) | 217,075 (+1,960) | 487,558 (+7,084) | +| 2025-09-03 | 274,793 (+4,310) | 219,755 (+2,680) | 494,548 (+6,990) | +| 2025-09-04 | 280,430 (+5,637) | 222,103 (+2,348) | 502,533 (+7,985) | +| 2025-09-05 | 283,769 (+3,339) | 223,793 (+1,690) | 507,562 (+5,029) | +| 2025-09-06 | 286,245 (+2,476) | 225,036 (+1,243) | 511,281 (+3,719) | +| 2025-09-07 | 288,623 (+2,378) | 225,866 (+830) | 514,489 (+3,208) | +| 2025-09-08 | 293,341 (+4,718) | 227,073 (+1,207) | 520,414 (+5,925) | +| 2025-09-09 | 300,036 (+6,695) | 229,788 (+2,715) | 529,824 (+9,410) | +| 2025-09-10 | 307,287 (+7,251) | 233,435 (+3,647) | 540,722 (+10,898) | +| 2025-09-11 | 314,083 (+6,796) | 237,356 (+3,921) | 551,439 (+10,717) | +| 2025-09-12 | 321,046 (+6,963) | 240,728 (+3,372) | 561,774 (+10,335) | +| 2025-09-13 | 324,894 (+3,848) | 245,539 (+4,811) | 570,433 (+8,659) | +| 2025-09-14 | 328,876 (+3,982) | 248,245 (+2,706) | 577,121 (+6,688) | +| 2025-09-15 | 334,201 (+5,325) | 250,983 (+2,738) | 585,184 (+8,063) | +| 2025-09-16 | 342,609 (+8,408) | 255,264 (+4,281) | 597,873 (+12,689) | +| 2025-09-17 | 351,117 (+8,508) | 260,970 (+5,706) | 612,087 (+14,214) | +| 2025-09-18 | 358,717 (+7,600) | 266,922 (+5,952) | 625,639 (+13,552) | +| 2025-09-19 | 365,401 (+6,684) | 271,859 (+4,937) | 637,260 (+11,621) | +| 2025-09-20 | 372,092 (+6,691) | 276,917 (+5,058) | 649,009 (+11,749) | +| 2025-09-21 | 377,079 (+4,987) | 280,261 (+3,344) | 657,340 (+8,331) | +| 2025-09-22 | 382,492 (+5,413) | 284,009 (+3,748) | 666,501 (+9,161) | +| 2025-09-23 | 387,008 (+4,516) | 289,129 (+5,120) | 676,137 (+9,636) | +| 2025-09-24 | 393,325 (+6,317) | 294,927 (+5,798) | 688,252 (+12,115) | +| 2025-09-25 | 398,879 (+5,554) | 301,663 (+6,736) | 700,542 (+12,290) | +| 2025-09-26 | 404,334 (+5,455) | 306,713 (+5,050) | 711,047 (+10,505) | +| 2025-09-27 | 411,618 (+7,284) | 317,763 (+11,050) | 729,381 (+18,334) | +| 2025-09-28 | 414,910 (+3,292) | 322,522 (+4,759) | 737,432 (+8,051) | +| 2025-09-29 | 419,919 (+5,009) | 328,033 (+5,511) | 747,952 (+10,520) | +| 2025-09-30 | 427,991 (+8,072) | 336,472 (+8,439) | 764,463 (+16,511) | +| 2025-10-01 | 433,591 (+5,600) | 341,742 (+5,270) | 775,333 (+10,870) | +| 2025-10-02 | 440,852 (+7,261) | 348,099 (+6,357) | 788,951 (+13,618) | +| 2025-10-03 | 446,829 (+5,977) | 359,937 (+11,838) | 806,766 (+17,815) | +| 2025-10-04 | 452,561 (+5,732) | 370,386 (+10,449) | 822,947 (+16,181) | +| 2025-10-05 | 455,559 (+2,998) | 374,745 (+4,359) | 830,304 (+7,357) | +| 2025-10-06 | 460,927 (+5,368) | 379,489 (+4,744) | 840,416 (+10,112) | +| 2025-10-07 | 467,336 (+6,409) | 385,438 (+5,949) | 852,774 (+12,358) | +| 2025-10-08 | 474,643 (+7,307) | 394,139 (+8,701) | 868,782 (+16,008) | +| 2025-10-09 | 479,203 (+4,560) | 400,526 (+6,387) | 879,729 (+10,947) | +| 2025-10-10 | 484,374 (+5,171) | 406,015 (+5,489) | 890,389 (+10,660) | +| 2025-10-11 | 488,427 (+4,053) | 414,699 (+8,684) | 903,126 (+12,737) | +| 2025-10-12 | 492,125 (+3,698) | 418,745 (+4,046) | 910,870 (+7,744) | +| 2025-10-14 | 505,130 (+13,005) | 429,286 (+10,541) | 934,416 (+23,546) | +| 2025-10-15 | 512,717 (+7,587) | 439,290 (+10,004) | 952,007 (+17,591) | +| 2025-10-16 | 517,719 (+5,002) | 447,137 (+7,847) | 964,856 (+12,849) | +| 2025-10-17 | 526,239 (+8,520) | 457,467 (+10,330) | 983,706 (+18,850) | +| 2025-10-18 | 531,564 (+5,325) | 465,272 (+7,805) | 996,836 (+13,130) | +| 2025-10-19 | 536,209 (+4,645) | 469,078 (+3,806) | 1,005,287 (+8,451) | +| 2025-10-20 | 541,264 (+5,055) | 472,952 (+3,874) | 1,014,216 (+8,929) | +| 2025-10-21 | 548,721 (+7,457) | 479,703 (+6,751) | 1,028,424 (+14,208) | +| 2025-10-22 | 557,949 (+9,228) | 491,395 (+11,692) | 1,049,344 (+20,920) | +| 2025-10-23 | 564,716 (+6,767) | 498,736 (+7,341) | 1,063,452 (+14,108) | +| 2025-10-24 | 572,692 (+7,976) | 506,905 (+8,169) | 1,079,597 (+16,145) | +| 2025-10-25 | 578,927 (+6,235) | 516,129 (+9,224) | 1,095,056 (+15,459) | +| 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) | +| 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) | +| 2025-10-28 | 595,776 (+5,777) | 532,438 (+6,437) | 1,128,214 (+12,214) | +| 2025-10-29 | 606,259 (+10,483) | 542,064 (+9,626) | 1,148,323 (+20,109) | +| 2025-10-30 | 613,746 (+7,487) | 542,064 (+0) | 1,155,810 (+7,487) | +| 2025-10-30 | 617,846 (+4,100) | 555,026 (+12,962) | 1,172,872 (+17,062) | +| 2025-10-31 | 626,612 (+8,766) | 564,579 (+9,553) | 1,191,191 (+18,319) | +| 2025-11-01 | 636,100 (+9,488) | 581,806 (+17,227) | 1,217,906 (+26,715) | +| 2025-11-02 | 644,067 (+7,967) | 590,004 (+8,198) | 1,234,071 (+16,165) | +| 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) | +| 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) | +| 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) | +| 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) | +| 2025-11-07 | 696,646 (+10,394) | 642,146 (+11,261) | 1,338,792 (+21,655) | +| 2025-11-08 | 706,035 (+9,389) | 653,489 (+11,343) | 1,359,524 (+20,732) | +| 2025-11-09 | 713,462 (+7,427) | 660,459 (+6,970) | 1,373,921 (+14,397) | +| 2025-11-10 | 722,288 (+8,826) | 668,225 (+7,766) | 1,390,513 (+16,592) | +| 2025-11-11 | 729,769 (+7,481) | 677,501 (+9,276) | 1,407,270 (+16,757) | +| 2025-11-12 | 740,180 (+10,411) | 686,454 (+8,953) | 1,426,634 (+19,364) | +| 2025-11-13 | 749,905 (+9,725) | 696,157 (+9,703) | 1,446,062 (+19,428) | +| 2025-11-14 | 759,928 (+10,023) | 705,237 (+9,080) | 1,465,165 (+19,103) | +| 2025-11-15 | 765,955 (+6,027) | 712,870 (+7,633) | 1,478,825 (+13,660) | +| 2025-11-16 | 771,069 (+5,114) | 716,596 (+3,726) | 1,487,665 (+8,840) | +| 2025-11-17 | 780,161 (+9,092) | 723,339 (+6,743) | 1,503,500 (+15,835) | +| 2025-11-18 | 791,563 (+11,402) | 732,544 (+9,205) | 1,524,107 (+20,607) | +| 2025-11-19 | 804,409 (+12,846) | 747,624 (+15,080) | 1,552,033 (+27,926) | +| 2025-11-20 | 814,620 (+10,211) | 757,907 (+10,283) | 1,572,527 (+20,494) | +| 2025-11-21 | 826,309 (+11,689) | 769,307 (+11,400) | 1,595,616 (+23,089) | +| 2025-11-22 | 837,269 (+10,960) | 780,996 (+11,689) | 1,618,265 (+22,649) | +| 2025-11-23 | 846,609 (+9,340) | 795,069 (+14,073) | 1,641,678 (+23,413) | +| 2025-11-24 | 856,733 (+10,124) | 804,033 (+8,964) | 1,660,766 (+19,088) | +| 2025-11-25 | 869,423 (+12,690) | 817,339 (+13,306) | 1,686,762 (+25,996) | +| 2025-11-26 | 881,414 (+11,991) | 832,518 (+15,179) | 1,713,932 (+27,170) | +| 2025-11-27 | 893,960 (+12,546) | 846,180 (+13,662) | 1,740,140 (+26,208) | +| 2025-11-28 | 901,741 (+7,781) | 856,482 (+10,302) | 1,758,223 (+18,083) | +| 2025-11-29 | 908,689 (+6,948) | 863,361 (+6,879) | 1,772,050 (+13,827) | +| 2025-11-30 | 916,116 (+7,427) | 870,194 (+6,833) | 1,786,310 (+14,260) | +| 2025-12-01 | 925,898 (+9,782) | 876,500 (+6,306) | 1,802,398 (+16,088) | +| 2025-12-02 | 939,250 (+13,352) | 890,919 (+14,419) | 1,830,169 (+27,771) | +| 2025-12-03 | 952,249 (+12,999) | 903,713 (+12,794) | 1,855,962 (+25,793) | +| 2025-12-04 | 965,611 (+13,362) | 916,471 (+12,758) | 1,882,082 (+26,120) | +| 2025-12-05 | 977,996 (+12,385) | 930,616 (+14,145) | 1,908,612 (+26,530) | +| 2025-12-06 | 987,884 (+9,888) | 943,773 (+13,157) | 1,931,657 (+23,045) | +| 2025-12-07 | 994,046 (+6,162) | 951,425 (+7,652) | 1,945,471 (+13,814) | +| 2025-12-08 | 1,000,898 (+6,852) | 957,149 (+5,724) | 1,958,047 (+12,576) | +| 2025-12-09 | 1,011,488 (+10,590) | 973,922 (+16,773) | 1,985,410 (+27,363) | +| 2025-12-10 | 1,025,891 (+14,403) | 991,708 (+17,786) | 2,017,599 (+32,189) | +| 2025-12-11 | 1,045,110 (+19,219) | 1,010,559 (+18,851) | 2,055,669 (+38,070) | +| 2025-12-12 | 1,061,340 (+16,230) | 1,030,838 (+20,279) | 2,092,178 (+36,509) | +| 2025-12-13 | 1,073,561 (+12,221) | 1,044,608 (+13,770) | 2,118,169 (+25,991) | +| 2025-12-14 | 1,082,042 (+8,481) | 1,052,425 (+7,817) | 2,134,467 (+16,298) | +| 2025-12-15 | 1,093,632 (+11,590) | 1,059,078 (+6,653) | 2,152,710 (+18,243) | +| 2025-12-16 | 1,120,477 (+26,845) | 1,078,022 (+18,944) | 2,198,499 (+45,789) | +| 2025-12-17 | 1,151,067 (+30,590) | 1,097,661 (+19,639) | 2,248,728 (+50,229) | +| 2025-12-18 | 1,178,658 (+27,591) | 1,113,418 (+15,757) | 2,292,076 (+43,348) | +| 2025-12-19 | 1,203,485 (+24,827) | 1,129,698 (+16,280) | 2,333,183 (+41,107) | +| 2025-12-20 | 1,223,000 (+19,515) | 1,146,258 (+16,560) | 2,369,258 (+36,075) | +| 2025-12-21 | 1,242,675 (+19,675) | 1,158,909 (+12,651) | 2,401,584 (+32,326) | +| 2025-12-22 | 1,262,522 (+19,847) | 1,169,121 (+10,212) | 2,431,643 (+30,059) | +| 2025-12-23 | 1,286,548 (+24,026) | 1,186,439 (+17,318) | 2,472,987 (+41,344) | +| 2025-12-24 | 1,309,323 (+22,775) | 1,203,767 (+17,328) | 2,513,090 (+40,103) | +| 2025-12-25 | 1,333,032 (+23,709) | 1,217,283 (+13,516) | 2,550,315 (+37,225) | +| 2025-12-26 | 1,352,411 (+19,379) | 1,227,615 (+10,332) | 2,580,026 (+29,711) | +| 2025-12-27 | 1,371,771 (+19,360) | 1,238,236 (+10,621) | 2,610,007 (+29,981) | +| 2025-12-28 | 1,390,388 (+18,617) | 1,245,690 (+7,454) | 2,636,078 (+26,071) | +| 2025-12-29 | 1,415,560 (+25,172) | 1,257,101 (+11,411) | 2,672,661 (+36,583) | +| 2025-12-30 | 1,445,450 (+29,890) | 1,272,689 (+15,588) | 2,718,139 (+45,478) | +| 2025-12-31 | 1,479,598 (+34,148) | 1,293,235 (+20,546) | 2,772,833 (+54,694) | +| 2026-01-01 | 1,508,883 (+29,285) | 1,309,874 (+16,639) | 2,818,757 (+45,924) | +| 2026-01-02 | 1,563,474 (+54,591) | 1,320,959 (+11,085) | 2,884,433 (+65,676) | +| 2026-01-03 | 1,618,065 (+54,591) | 1,331,914 (+10,955) | 2,949,979 (+65,546) | +| 2026-01-04 | 1,672,656 (+39,702) | 1,339,883 (+7,969) | 3,012,539 (+62,560) | +| 2026-01-05 | 1,738,171 (+65,515) | 1,353,043 (+13,160) | 3,091,214 (+78,675) | +| 2026-01-06 | 1,960,988 (+222,817) | 1,377,377 (+24,334) | 3,338,365 (+247,151) | +| 2026-01-07 | 2,123,239 (+162,251) | 1,398,648 (+21,271) | 3,521,887 (+183,522) | +| 2026-01-08 | 2,272,630 (+149,391) | 1,432,480 (+33,832) | 3,705,110 (+183,223) | +| 2026-01-09 | 2,443,565 (+170,935) | 1,469,451 (+36,971) | 3,913,016 (+207,906) | +| 2026-01-10 | 2,632,023 (+188,458) | 1,503,670 (+34,219) | 4,135,693 (+222,677) | +| 2026-01-11 | 2,836,394 (+204,371) | 1,530,479 (+26,809) | 4,366,873 (+231,180) | +| 2026-01-12 | 3,053,594 (+217,200) | 1,553,671 (+23,192) | 4,607,265 (+240,392) | +| 2026-01-13 | 3,297,078 (+243,484) | 1,595,062 (+41,391) | 4,892,140 (+284,875) | +| 2026-01-14 | 3,568,928 (+271,850) | 1,645,362 (+50,300) | 5,214,290 (+322,150) | +| 2026-01-16 | 4,121,550 (+552,622) | 1,754,418 (+109,056) | 5,875,968 (+661,678) | +| 2026-01-17 | 4,389,558 (+268,008) | 1,805,315 (+50,897) | 6,194,873 (+318,905) | +| 2026-01-18 | 4,627,623 (+238,065) | 1,839,171 (+33,856) | 6,466,794 (+271,921) | +| 2026-01-19 | 4,861,108 (+233,485) | 1,863,112 (+23,941) | 6,724,220 (+257,426) | +| 2026-01-20 | 5,128,999 (+267,891) | 1,903,665 (+40,553) | 7,032,664 (+308,444) | +| 2026-01-21 | 5,444,842 (+315,843) | 1,962,531 (+58,866) | 7,407,373 (+374,709) | +| 2026-01-22 | 5,766,340 (+321,498) | 2,029,487 (+66,956) | 7,795,827 (+388,454) | diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md new file mode 100644 index 00000000000..52d012fcb97 --- /dev/null +++ b/STYLE_GUIDE.md @@ -0,0 +1,71 @@ +## Style Guide + +- Keep things in one function unless composable or reusable +- Avoid unnecessary destructuring. Instead of `const { a, b } = obj`, use `obj.a` and `obj.b` to preserve context +- Avoid `try`/`catch` where possible +- Avoid using the `any` type +- Prefer single word variable names where possible +- Use Bun APIs when possible, like `Bun.file()` + +# Avoid let statements + +We don't like `let` statements, especially combined with if/else statements. +Prefer `const`. + +Good: + +```ts +const foo = condition ? 1 : 2 +``` + +Bad: + +```ts +let foo + +if (condition) foo = 1 +else foo = 2 +``` + +# Avoid else statements + +Prefer early returns or using an `iife` to avoid else statements. + +Good: + +```ts +function foo() { + if (condition) return 1 + return 2 +} +``` + +Bad: + +```ts +function foo() { + if (condition) return 1 + else return 2 +} +``` + +# Prefer single word naming + +Try your best to find a single word name for your variables, functions, etc. +Only use multiple words if you cannot. + +Good: + +```ts +const foo = 1 +const bar = 2 +const baz = 3 +``` + +Bad: + +```ts +const fooBar = 1 +const barBaz = 2 +const bazFoo = 3 +``` diff --git a/bun.lock b/bun.lock index eb8c53d2f40..835fd183f56 100644 --- a/bun.lock +++ b/bun.lock @@ -1,171 +1,462 @@ { "lockfileVersion": 1, + "configVersion": 1, "workspaces": { "": { "name": "opencode", "dependencies": { - "pulumi-stripe": "0.0.24", + "@aws-sdk/client-s3": "3.933.0", + "@opencode-ai/plugin": "workspace:*", + "@opencode-ai/script": "workspace:*", + "@opencode-ai/sdk": "workspace:*", + "typescript": "catalog:", + }, + "devDependencies": { + "@actions/artifact": "5.0.1", + "@tsconfig/bun": "catalog:", + "husky": "9.1.7", + "prettier": "3.6.2", + "semver": "^7.6.0", + "sst": "3.17.23", + "turbo": "2.5.6", + }, + }, + "packages/app": { + "name": "@opencode-ai/app", + "version": "1.1.32", + "dependencies": { + "@kobalte/core": "catalog:", + "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@opencode-ai/util": "workspace:*", + "@shikijs/transformers": "3.9.2", + "@solid-primitives/active-element": "2.1.3", + "@solid-primitives/audio": "1.4.2", + "@solid-primitives/event-bus": "1.1.2", + "@solid-primitives/i18n": "2.2.1", + "@solid-primitives/media": "2.3.3", + "@solid-primitives/resize-observer": "2.1.3", + "@solid-primitives/scroll": "2.1.3", + "@solid-primitives/storage": "catalog:", + "@solid-primitives/websocket": "1.3.1", + "@solidjs/meta": "catalog:", + "@solidjs/router": "catalog:", + "@thisbeyond/solid-dnd": "0.7.5", + "diff": "catalog:", + "fuzzysort": "catalog:", + "ghostty-web": "0.3.0", + "luxon": "catalog:", + "marked": "catalog:", + "marked-shiki": "catalog:", + "remeda": "catalog:", + "shiki": "catalog:", + "solid-js": "catalog:", + "solid-list": "catalog:", + "tailwindcss": "catalog:", + "virtua": "catalog:", + "zod": "catalog:", }, "devDependencies": { - "prettier": "3.5.3", - "sst": "3.17.8", + "@happy-dom/global-registrator": "20.0.11", + "@playwright/test": "1.57.0", + "@tailwindcss/vite": "catalog:", + "@tsconfig/bun": "1.0.9", + "@types/bun": "catalog:", + "@types/luxon": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + "vite-plugin-icons-spritesheet": "3.0.1", + "vite-plugin-solid": "catalog:", }, }, - "cloud/app": { - "name": "@opencode/cloud-app", + "packages/console/app": { + "name": "@opencode-ai/console-app", + "version": "1.1.32", "dependencies": { + "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", - "@openauthjs/openauth": "0.0.0-20250322224806", - "@opencode/cloud-core": "workspace:*", - "@solidjs/meta": "^0.29.4", - "@solidjs/router": "^0.15.0", - "@solidjs/start": "^1.1.0", - "solid-js": "^1.9.5", - "vinxi": "^0.5.7", + "@jsx-email/render": "1.1.1", + "@kobalte/core": "catalog:", + "@openauthjs/openauth": "catalog:", + "@opencode-ai/console-core": "workspace:*", + "@opencode-ai/console-mail": "workspace:*", + "@opencode-ai/console-resource": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@smithy/eventstream-codec": "4.2.7", + "@smithy/util-utf8": "4.2.0", + "@solidjs/meta": "catalog:", + "@solidjs/router": "catalog:", + "@solidjs/start": "catalog:", + "@stripe/stripe-js": "8.6.1", + "chart.js": "4.5.1", + "nitro": "3.0.1-alpha.1", + "solid-js": "catalog:", + "solid-list": "0.3.0", + "solid-stripe": "0.8.1", + "vite": "catalog:", + "zod": "catalog:", + }, + "devDependencies": { + "@typescript/native-preview": "catalog:", + "@webgpu/types": "0.1.54", + "typescript": "catalog:", + "wrangler": "4.50.0", }, }, - "cloud/core": { - "name": "@opencode/cloud-core", - "version": "0.5.12", + "packages/console/core": { + "name": "@opencode-ai/console-core", + "version": "1.1.32", "dependencies": { "@aws-sdk/client-sts": "3.782.0", + "@jsx-email/render": "1.1.1", + "@opencode-ai/console-mail": "workspace:*", + "@opencode-ai/console-resource": "workspace:*", + "@planetscale/database": "1.19.0", + "aws4fetch": "1.0.20", "drizzle-orm": "0.41.0", "postgres": "3.4.7", "stripe": "18.0.0", - "ulid": "3.0.0", + "ulid": "catalog:", + "zod": "catalog:", }, "devDependencies": { + "@cloudflare/workers-types": "catalog:", + "@tsconfig/node22": "22.0.2", + "@types/bun": "1.3.0", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", "drizzle-kit": "0.30.5", + "mysql2": "3.14.4", + "typescript": "catalog:", }, }, - "cloud/function": { - "name": "@opencode/cloud-function", - "version": "0.5.12", + "packages/console/function": { + "name": "@opencode-ai/console-function", + "version": "1.1.32", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", "@ai-sdk/openai-compatible": "1.0.1", "@hono/zod-validator": "catalog:", "@openauthjs/openauth": "0.0.0-20250322224806", + "@opencode-ai/console-core": "workspace:*", + "@opencode-ai/console-resource": "workspace:*", "ai": "catalog:", "hono": "catalog:", "zod": "catalog:", }, "devDependencies": { - "@cloudflare/workers-types": "4.20250522.0", + "@cloudflare/workers-types": "catalog:", + "@tsconfig/node22": "22.0.2", "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", "openai": "5.11.0", "typescript": "catalog:", }, }, - "cloud/web": { - "name": "@opencode/cloud-web", - "version": "0.5.12", + "packages/console/mail": { + "name": "@opencode-ai/console-mail", + "version": "1.1.32", "dependencies": { - "@kobalte/core": "0.13.9", - "@openauthjs/solid": "0.0.0-20250322224806", - "@solid-primitives/storage": "4.3.1", - "@solidjs/meta": "0.29.4", - "@solidjs/router": "0.15.3", - "solid-js": "1.9.5", - "solid-list": "0.3.0", + "@jsx-email/all": "2.2.3", + "@jsx-email/cli": "1.4.3", + "@tsconfig/bun": "1.0.9", + "@types/react": "18.0.25", + "react": "18.2.0", + "solid-js": "catalog:", + }, + }, + "packages/console/resource": { + "name": "@opencode-ai/console-resource", + "dependencies": { + "@cloudflare/workers-types": "catalog:", + }, + "devDependencies": { + "@cloudflare/workers-types": "catalog:", + "@tsconfig/node22": "22.0.2", + "@types/node": "catalog:", + "cloudflare": "5.2.0", + }, + }, + "packages/desktop": { + "name": "@opencode-ai/desktop", + "version": "1.1.32", + "dependencies": { + "@opencode-ai/app": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@solid-primitives/storage": "catalog:", + "@tauri-apps/api": "^2", + "@tauri-apps/plugin-dialog": "~2", + "@tauri-apps/plugin-http": "~2", + "@tauri-apps/plugin-notification": "~2", + "@tauri-apps/plugin-opener": "^2", + "@tauri-apps/plugin-os": "~2", + "@tauri-apps/plugin-process": "~2", + "@tauri-apps/plugin-shell": "~2", + "@tauri-apps/plugin-store": "~2", + "@tauri-apps/plugin-updater": "~2", + "@tauri-apps/plugin-window-state": "~2", + "solid-js": "catalog:", }, "devDependencies": { + "@actions/artifact": "4.0.0", + "@tauri-apps/cli": "^2", + "@types/bun": "catalog:", + "@typescript/native-preview": "catalog:", + "typescript": "~5.6.2", + "vite": "catalog:", + }, + }, + "packages/enterprise": { + "name": "@opencode-ai/enterprise", + "version": "1.1.32", + "dependencies": { + "@opencode-ai/ui": "workspace:*", + "@opencode-ai/util": "workspace:*", + "@pierre/diffs": "catalog:", + "@solidjs/meta": "catalog:", + "@solidjs/router": "catalog:", + "@solidjs/start": "catalog:", + "aws4fetch": "^1.0.20", + "hono": "catalog:", + "hono-openapi": "catalog:", + "js-base64": "3.7.7", + "luxon": "catalog:", + "nitro": "3.0.1-alpha.1", + "solid-js": "catalog:", + "zod": "catalog:", + }, + "devDependencies": { + "@cloudflare/workers-types": "catalog:", + "@tailwindcss/vite": "catalog:", + "@types/luxon": "catalog:", + "@typescript/native-preview": "catalog:", + "tailwindcss": "catalog:", "typescript": "catalog:", - "vite": "6.2.2", - "vite-plugin-pages": "0.32.5", - "vite-plugin-solid": "2.11.6", + "vite": "catalog:", }, }, "packages/function": { - "name": "@opencode/function", - "version": "0.5.12", + "name": "@opencode-ai/function", + "version": "1.1.32", "dependencies": { "@octokit/auth-app": "8.0.1", - "@octokit/rest": "22.0.0", + "@octokit/rest": "catalog:", "hono": "catalog:", "jose": "6.0.11", }, "devDependencies": { - "@cloudflare/workers-types": "4.20250522.0", + "@cloudflare/workers-types": "catalog:", + "@tsconfig/node22": "22.0.2", "@types/node": "catalog:", "typescript": "catalog:", }, }, "packages/opencode": { "name": "opencode", - "version": "0.5.12", + "version": "1.1.32", "bin": { "opencode": "./bin/opencode", }, "dependencies": { + "@actions/core": "1.11.1", + "@actions/github": "6.0.1", + "@agentclientprotocol/sdk": "0.12.0", + "@ai-sdk/amazon-bedrock": "3.0.73", + "@ai-sdk/anthropic": "2.0.57", + "@ai-sdk/azure": "2.0.91", + "@ai-sdk/cerebras": "1.0.34", + "@ai-sdk/cohere": "2.0.22", + "@ai-sdk/deepinfra": "1.0.31", + "@ai-sdk/gateway": "2.0.25", + "@ai-sdk/google": "2.0.52", + "@ai-sdk/google-vertex": "3.0.97", + "@ai-sdk/groq": "2.0.34", + "@ai-sdk/mistral": "2.0.27", + "@ai-sdk/openai": "2.0.89", + "@ai-sdk/openai-compatible": "1.0.30", + "@ai-sdk/perplexity": "2.0.23", + "@ai-sdk/provider": "2.0.1", + "@ai-sdk/provider-utils": "3.0.20", + "@ai-sdk/togetherai": "1.0.31", + "@ai-sdk/vercel": "1.0.31", + "@ai-sdk/xai": "2.0.51", "@clack/prompts": "1.0.0-alpha.1", + "@gitlab/gitlab-ai-provider": "3.1.3", + "@hono/standard-validator": "0.1.5", "@hono/zod-validator": "catalog:", - "@modelcontextprotocol/sdk": "1.15.1", - "@openauthjs/openauth": "0.4.3", + "@modelcontextprotocol/sdk": "1.25.2", + "@octokit/graphql": "9.0.2", + "@octokit/rest": "catalog:", + "@openauthjs/openauth": "catalog:", "@opencode-ai/plugin": "workspace:*", + "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/util": "workspace:*", + "@openrouter/ai-sdk-provider": "1.5.2", + "@opentui/core": "0.1.74", + "@opentui/solid": "0.1.74", + "@parcel/watcher": "2.5.1", + "@pierre/diffs": "catalog:", + "@solid-primitives/event-bus": "1.1.2", + "@solid-primitives/scheduled": "1.5.2", "@standard-schema/spec": "1.0.0", "@zip.js/zip.js": "2.7.62", "ai": "catalog:", + "bonjour-service": "1.3.0", + "bun-pty": "0.4.4", + "chokidar": "4.0.3", + "clipboardy": "4.0.0", "decimal.js": "10.5.0", - "diff": "8.0.2", + "diff": "catalog:", + "fuzzysort": "3.1.0", "gray-matter": "4.0.3", "hono": "catalog:", - "hono-openapi": "0.4.8", - "isomorphic-git": "1.32.1", + "hono-openapi": "catalog:", + "ignore": "7.0.5", "jsonc-parser": "3.3.1", "minimatch": "10.0.3", "open": "10.1.2", + "opentui-spinner": "0.0.6", + "partial-json": "0.1.7", "remeda": "catalog:", - "tree-sitter": "0.22.4", - "tree-sitter-bash": "0.23.3", + "solid-js": "catalog:", + "strip-ansi": "7.1.2", + "tree-sitter-bash": "0.25.0", "turndown": "7.2.0", - "ulid": "3.0.1", + "ulid": "catalog:", "vscode-jsonrpc": "8.2.1", - "web-tree-sitter": "0.22.6", + "web-tree-sitter": "0.25.10", "xdg-basedir": "5.1.0", "yargs": "18.0.0", "zod": "catalog:", - "zod-openapi": "4.1.0", + "zod-to-json-schema": "3.24.5", }, "devDependencies": { - "@ai-sdk/amazon-bedrock": "2.2.10", + "@babel/core": "7.28.4", "@octokit/webhooks-types": "7.6.1", + "@opencode-ai/script": "workspace:*", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1", "@standard-schema/spec": "1.0.0", - "@tsconfig/bun": "1.0.7", - "@types/bun": "latest", + "@tsconfig/bun": "catalog:", + "@types/babel__core": "7.20.5", + "@types/bun": "catalog:", "@types/turndown": "5.0.5", "@types/yargs": "17.0.33", + "@typescript/native-preview": "catalog:", "typescript": "catalog:", "vscode-languageserver-types": "3.17.5", + "why-is-node-running": "3.2.2", "zod-to-json-schema": "3.24.5", }, }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "0.5.12", + "version": "1.1.32", "dependencies": { "@opencode-ai/sdk": "workspace:*", + "zod": "catalog:", }, "devDependencies": { - "@hey-api/openapi-ts": "0.80.1", "@tsconfig/node22": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", "typescript": "catalog:", }, }, + "packages/script": { + "name": "@opencode-ai/script", + "devDependencies": { + "@types/bun": "catalog:", + }, + }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "0.5.12", + "version": "1.1.32", + "devDependencies": { + "@hey-api/openapi-ts": "0.90.4", + "@tsconfig/node22": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "typescript": "catalog:", + }, + }, + "packages/slack": { + "name": "@opencode-ai/slack", + "version": "1.1.32", + "dependencies": { + "@opencode-ai/sdk": "workspace:*", + "@slack/bolt": "^3.17.1", + }, + "devDependencies": { + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "typescript": "catalog:", + }, + }, + "packages/ui": { + "name": "@opencode-ai/ui", + "version": "1.1.32", + "dependencies": { + "@kobalte/core": "catalog:", + "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/util": "workspace:*", + "@pierre/diffs": "catalog:", + "@shikijs/transformers": "3.9.2", + "@solid-primitives/bounds": "0.1.3", + "@solid-primitives/media": "2.3.3", + "@solid-primitives/resize-observer": "2.1.3", + "@solidjs/meta": "catalog:", + "@typescript/native-preview": "catalog:", + "dompurify": "3.3.1", + "fuzzysort": "catalog:", + "katex": "0.16.27", + "luxon": "catalog:", + "marked": "catalog:", + "marked-katex-extension": "5.1.6", + "marked-shiki": "catalog:", + "remeda": "catalog:", + "shiki": "catalog:", + "solid-js": "catalog:", + "solid-list": "catalog:", + "strip-ansi": "7.1.2", + "virtua": "catalog:", + }, "devDependencies": { - "@hey-api/openapi-ts": "0.80.1", + "@tailwindcss/vite": "catalog:", "@tsconfig/node22": "catalog:", + "@types/bun": "catalog:", + "@types/katex": "0.16.7", + "@types/luxon": "catalog:", + "tailwindcss": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + "vite-plugin-icons-spritesheet": "3.0.1", + "vite-plugin-solid": "catalog:", + }, + }, + "packages/util": { + "name": "@opencode-ai/util", + "version": "1.1.32", + "dependencies": { + "zod": "catalog:", + }, + "devDependencies": { + "@types/bun": "catalog:", "typescript": "catalog:", }, }, "packages/web": { - "name": "@opencode/web", - "version": "0.5.12", + "name": "@opencode-ai/web", + "version": "1.1.32", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -173,21 +464,20 @@ "@astrojs/starlight": "0.34.3", "@fontsource/ibm-plex-mono": "5.2.5", "@shikijs/transformers": "3.4.2", - "@types/luxon": "3.6.2", + "@types/luxon": "catalog:", "ai": "catalog:", "astro": "5.7.13", - "diff": "8.0.2", + "diff": "catalog:", "js-base64": "3.7.7", "lang-map": "0.4.0", - "luxon": "3.6.1", - "marked": "15.0.12", - "marked-shiki": "1.2.1", + "luxon": "catalog:", + "marked": "catalog:", + "marked-shiki": "catalog:", "rehype-autolink-headings": "7.1.0", - "remeda": "2.26.0", - "sharp": "0.32.5", - "shiki": "3.4.2", - "solid-js": "1.9.7", - "toolbeam-docs-theme": "0.4.5", + "remeda": "catalog:", + "shiki": "catalog:", + "solid-js": "catalog:", + "toolbeam-docs-theme": "0.4.8", }, "devDependencies": { "@types/node": "catalog:", @@ -197,55 +487,134 @@ }, }, "trustedDependencies": [ - "sharp", "esbuild", - "protobufjs", - "tree-sitter", "web-tree-sitter", "tree-sitter-bash", ], + "patchedDependencies": { + "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch", + }, + "overrides": { + "@types/bun": "catalog:", + "@types/node": "catalog:", + }, "catalog": { + "@cloudflare/workers-types": "4.20251008.0", "@hono/zod-validator": "0.4.2", + "@kobalte/core": "0.13.11", + "@octokit/rest": "22.0.0", + "@openauthjs/openauth": "0.0.0-20250322224806", + "@pierre/diffs": "1.0.2", + "@playwright/test": "1.51.0", + "@solid-primitives/storage": "4.3.3", + "@solidjs/meta": "0.29.4", + "@solidjs/router": "0.15.4", + "@solidjs/start": "https://pkg.pr.new/@solidjs/start@dfb2020", + "@tailwindcss/vite": "4.1.11", + "@tsconfig/bun": "1.0.9", "@tsconfig/node22": "22.0.2", + "@types/bun": "1.3.5", + "@types/luxon": "3.7.1", "@types/node": "22.13.9", - "ai": "5.0.8", - "hono": "4.7.10", + "@types/semver": "7.7.1", + "@typescript/native-preview": "7.0.0-dev.20251207.1", + "ai": "5.0.119", + "diff": "8.0.2", + "dompurify": "3.3.1", + "fuzzysort": "3.1.0", + "hono": "4.10.7", + "hono-openapi": "1.1.2", + "luxon": "3.6.1", + "marked": "17.0.1", + "marked-shiki": "1.2.1", "remeda": "2.26.0", + "shiki": "3.20.0", + "solid-js": "1.9.10", + "solid-list": "0.3.0", + "tailwindcss": "4.1.11", "typescript": "5.8.2", - "zod": "3.25.76", + "ulid": "3.0.1", + "virtua": "0.42.3", + "vite": "7.1.4", + "vite-plugin-solid": "2.11.10", + "zod": "4.1.8", }, "packages": { - "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@2.2.10", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icLGO7Q0NinnHIPgT+y1QjHVwH4HwV+brWbvM+FfCG2Afpa89PyKa3Ret91kGjZpBgM/xnj1B7K5eM+rRlsXQA=="], + "@actions/artifact": ["@actions/artifact@5.0.1", "", { "dependencies": { "@actions/core": "^2.0.0", "@actions/github": "^6.0.1", "@actions/http-client": "^3.0.0", "@azure/storage-blob": "^12.29.1", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-dHJ5rHduhCKUikKTT9eXeWoUvfKia3IjR1sO/VTAV3DVAL4yMTRnl2iO5mcfiBjySHLwPNezwENAVskKYU5ymw=="], + + "@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="], + + "@actions/exec": ["@actions/exec@1.1.1", "", { "dependencies": { "@actions/io": "^1.0.1" } }, "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w=="], + + "@actions/github": ["@actions/github@6.0.1", "", { "dependencies": { "@actions/http-client": "^2.2.0", "@octokit/core": "^5.0.1", "@octokit/plugin-paginate-rest": "^9.2.2", "@octokit/plugin-rest-endpoint-methods": "^10.4.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "undici": "^5.28.5" } }, "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw=="], + + "@actions/http-client": ["@actions/http-client@3.0.0", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.28.5" } }, "sha512-1s3tXAfVMSz9a4ZEBkXXRQD4QhY3+GAsWSbaYpeknPOKEeyRiU3lH+bHiLMZdo2x/fIeQ/hscL1wCkDLVM2DZQ=="], + + "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], + + "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], + + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.12.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-V8uH/KK1t7utqyJmTA7y7DzKu6+jKFIXM+ZVouz8E55j8Ej2RV42rEvPKn3/PpBJlliI5crcGk1qQhZ7VwaepA=="], + + "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@3.0.73", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.57", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-EAAGJ/dfbAZaqIhK3w52hq6cftSLZwXdC6uHKh8Cls1T0N4MxS6ykDf54UyFO3bZWkQxR+Mdw1B3qireGOxtJQ=="], "@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-uyyaO4KhxoIKZztREqLPh+6/K3ZJx/rp72JKoUEL9/kC+vfQTThUfPnY/bUryUpcnawx8IY/tSoYNOi/8PCv7w=="], - "@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.4", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-1roLdgMbFU3Nr4MC97/te7w6OqxsWBkDUkpbCcvxF3jz/ku91WVaJldn/PKU8feMKNyI5W9wnqhbjb1BqbExOQ=="], + "@ai-sdk/azure": ["@ai-sdk/azure@2.0.91", "", { "dependencies": { "@ai-sdk/openai": "2.0.89", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-9tznVSs6LGQNKKxb8pKd7CkBV9yk+a/ENpFicHCj2CmBUKefxzwJ9JbUqrlK3VF6dGZw3LXq0dWxt7/Yekaj1w=="], + + "@ai-sdk/cerebras": ["@ai-sdk/cerebras@1.0.34", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XOK0dJsAGoPYi/lfR4KFBi8xhvJ46oCpAxUD6FmJAuJ4eh0qlj5zDt+myvzM8gvN7S6K7zHD+mdWlOPKGQT8Vg=="], + + "@ai-sdk/cohere": ["@ai-sdk/cohere@2.0.22", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-yJ9kP5cEDJwo8qpITq5TQFD8YNfNtW+HbyvWwrKMbFzmiMvIZuk95HIaFXE7PCTuZsqMA05yYu+qX/vQ3rNKjA=="], + + "@ai-sdk/deepinfra": ["@ai-sdk/deepinfra@1.0.31", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-87qFcYNvDF/89hB//MQjYTb3tlsAfmgeZrZ34RESeBTZpSgs0EzYOMqPMwFTHUNp4wteoifikDJbaS/9Da8cfw=="], + + "@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.25", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@vercel/oidc": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Rq+FX55ne7lMiqai7NcvvDZj4HLsr+hg77WayqmySqc6zhw3tIOLxd4Ty6OpwNj0C0bVMi3iCl2zvJIEirh9XA=="], + + "@ai-sdk/google": ["@ai-sdk/google@2.0.52", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2XUnGi3f7TV4ujoAhA+Fg3idUoG/+Y2xjCRg70a1/m0DH1KSQqYaCboJ1C19y6ZHGdf5KNT20eJdswP6TvrY2g=="], + + "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@3.0.97", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.57", "@ai-sdk/google": "2.0.52", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-s4tI7Z15i6FlbtCvS4SBRal8wRfkOXJzKxlS6cU4mJW/QfUfoVy4b22836NVNJwDvkG/HkDSfzwm/X8mn46MhA=="], + + "@ai-sdk/groq": ["@ai-sdk/groq@2.0.34", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-wfCYkVgmVjxNA32T57KbLabVnv9aFUflJ4urJ7eWgTwbnmGQHElCTu+rJ3ydxkXSqxOkXPwMOttDm7XNrvPjmg=="], + + "@ai-sdk/mistral": ["@ai-sdk/mistral@2.0.27", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-gaptHgaXjMw3+eA0Q4FABcsj5nQNP6EpFaGUR+Pj5WJy7Kn6mApl975/x57224MfeJIShNpt8wFKK3tvh5ewKg=="], "@ai-sdk/openai": ["@ai-sdk/openai@2.0.2", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-D4zYz2uR90aooKQvX1XnS00Z7PkbrcY+snUvPfm5bCabTG7bzLrVtD56nJ5bSaZG8lmuOMfXpyiEEArYLyWPpw=="], "@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.1", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-luHVcU+yKzwv3ekKgbP3v+elUVxb2Rt+8c6w9qi7g2NYG2/pEL21oIrnaEnc6UtTZLLZX9EFBcpq2N1FQKDIMw=="], - "@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="], + "@ai-sdk/perplexity": ["@ai-sdk/perplexity@2.0.23", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-aiaRvnc6mhQZKhTTSXPCjPH8Iqr5D/PfCN1hgVP/3RGTBbJtsd9HemIBSABeSdAKbsMH/PwJxgnqH75HEamcBA=="], + + "@ai-sdk/provider": ["@ai-sdk/provider@2.0.1", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng=="], + + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], - "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="], + "@ai-sdk/togetherai": ["@ai-sdk/togetherai@1.0.31", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RlYubjStoZQxna4Ng91Vvo8YskvL7lW9zj68IwZfCnaDBSAp1u6Nhc5BR4ZtKnY6PA3XEtu4bATIQl7yiiQ+Lw=="], + + "@ai-sdk/vercel": ["@ai-sdk/vercel@1.0.31", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ggvwAMt/KsbqcdR6ILQrjwrRONLV/8aG6rOLbjcOGvV0Ai+WdZRRKQj5nOeQ06PvwVQtKdkp7S4IinpXIhCiHg=="], + + "@ai-sdk/xai": ["@ai-sdk/xai@2.0.51", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-AI3le03qiegkZvn9hpnpDwez49lOvQLj4QUBT8H41SMbrdTYOxn3ktTwrsSu90cNDdzKGMvoH0u2GHju1EdnCg=="], + + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - "@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@11.9.3", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ=="], + "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.71.2", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ=="], + + "@anycable/core": ["@anycable/core@0.9.2", "", { "dependencies": { "nanoevents": "^7.0.1" } }, "sha512-x5ZXDcW/N4cxWl93CnbHs/u7qq4793jS2kNPWm+duPrXlrva+ml2ZGT7X9tuOBKzyIHf60zWCdIK7TUgMPAwXA=="], "@astrojs/cloudflare": ["@astrojs/cloudflare@12.6.3", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.1", "@astrojs/underscore-redirects": "1.0.0", "@cloudflare/workers-types": "^4.20250507.0", "tinyglobby": "^0.2.13", "vite": "^6.3.5", "wrangler": "^4.14.1" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-xhJptF5tU2k5eo70nIMyL1Udma0CqmUEnGSlGyFflLqSY82CRQI6nWZ/xZt0ZvmXuErUjIx0YYQNfZsz5CNjLQ=="], - "@astrojs/compiler": ["@astrojs/compiler@2.12.2", "", {}, "sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw=="], + "@astrojs/compiler": ["@astrojs/compiler@2.13.0", "", {}, "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw=="], "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.1", "", {}, "sha512-7dwEVigz9vUWDw3nRwLQ/yH/xYovlUA0ZD86xoeKEBmkz9O6iELG1yri67PgAPW6VLL/xInA4t7H0CK6VmtkKQ=="], "@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.1", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/prism": "3.2.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.1.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.1", "remark-smartypants": "^3.0.2", "shiki": "^3.0.0", "smol-toml": "^1.3.1", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg=="], - "@astrojs/mdx": ["@astrojs/mdx@4.3.1", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.3", "@mdx-js/mdx": "^3.1.0", "acorn": "^8.14.1", "es-module-lexer": "^1.6.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "kleur": "^4.1.5", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.4", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-0ynzkFd5p2IFDLPAfAcGizg44WyS0qUr43nP2vQkvrPlpoPEMeeoi1xWiWsVqQNaZ0FOmNqfUviUn52nm9mLag=="], + "@astrojs/mdx": ["@astrojs/mdx@4.3.12", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.9", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "piccolore": "^0.1.3", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-pL3CVPtuQrPnDhWjy7zqbOibNyPaxP4VpQS8T8spwKqKzauJ4yoKyNkVTD8jrP7EAJHmBhZ7PTmUGZqOpKKp8g=="], "@astrojs/prism": ["@astrojs/prism@3.2.0", "", { "dependencies": { "prismjs": "^1.29.0" } }, "sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw=="], - "@astrojs/sitemap": ["@astrojs/sitemap@3.4.2", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.24.4" } }, "sha512-wfN2dZzdkto6yaMtOFa/J9gc60YE3wl3rgSBoNJ+MU3lJVUMsDY9xf9uAVi8Mp/zEQKFDSJlQzBvqQUpw0Hf6g=="], + "@astrojs/sitemap": ["@astrojs/sitemap@3.6.0", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.25.76" } }, "sha512-4aHkvcOZBWJigRmMIAJwRQXBS+ayoP5z40OklTXYXhUDhwusz+DyDl+nSshY6y9DvkVEavwNcFO8FD81iGhXjg=="], "@astrojs/solid-js": ["@astrojs/solid-js@5.1.0", "", { "dependencies": { "vite": "^6.3.5", "vite-plugin-solid": "^2.11.6" }, "peerDependencies": { "solid-devtools": "^0.30.1", "solid-js": "^1.8.5" }, "optionalPeers": ["solid-devtools"] }, "sha512-VmPHOU9k7m6HHCT2Y1mNzifilUnttlowBM36frGcfj5wERJE9Ci0QtWJbzdf6AlcoIirb7xVw+ByupU011Di9w=="], @@ -257,6 +626,10 @@ "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], + "@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="], + + "@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="], + "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], @@ -265,71 +638,121 @@ "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], - "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg=="], + "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.933.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/credential-provider-node": "3.933.0", "@aws-sdk/middleware-bucket-endpoint": "3.930.0", "@aws-sdk/middleware-expect-continue": "3.930.0", "@aws-sdk/middleware-flexible-checksums": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-location-constraint": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-sdk-s3": "3.932.0", "@aws-sdk/middleware-ssec": "3.930.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/signature-v4-multi-region": "3.932.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-KxwZvdxdCeWK6o8mpnb+kk7Kgb8V+8AjTwSXUWH1UAD85B0tjdo1cSfE5zoR5fWGol4Ml5RLez12a6LPhsoTqA=="], + + "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.933.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zwGLSiK48z3PzKpQiDMKP85+fpIrPMF1qQOQW9OW7BGj5AuBZIisT2O4VzIgYJeh+t47MLU7VgBQL7muc+MJDg=="], "@aws-sdk/client-sts": ["@aws-sdk/client-sts@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/credential-provider-node": "3.782.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-Q1QLY3xE2z1trgriusP/6w40mI/yJjM524bN4gs+g6YX4sZGufpa7+Dj+JjL4fz8f9BCJ3ZlI+p4WxFxH7qvdQ=="], - "@aws-sdk/core": ["@aws-sdk/core@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/core": "^3.2.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/signature-v4": "^5.0.2", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA=="], + "@aws-sdk/core": ["@aws-sdk/core@3.932.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.2", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-AS8gypYQCbNojwgjvZGkJocC2CoEICDx9ZJ15ILsv+MlcCVLtUJSRSx3VzJOUY2EEIaGLRrPNlIqyn/9/fySvA=="], + + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.932.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/types": "3.930.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ozge/c7NdHUDyHqro6+P5oHt8wfKSUBN+olttiVfBe9Mw3wBMpPa3gQ0pZnG+gwBkKskBuip2bMR16tqYvUSEA=="], + + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.932.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/types": "3.930.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-b6N9Nnlg8JInQwzBkUq5spNaXssM3h3zLxGzpPrnw0nHSIWPJPTbZzA5Ca285fcDUFuKP+qf3qkuqlAjGOdWhg=="], + + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.933.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/credential-provider-env": "3.932.0", "@aws-sdk/credential-provider-http": "3.932.0", "@aws-sdk/credential-provider-process": "3.932.0", "@aws-sdk/credential-provider-sso": "3.933.0", "@aws-sdk/credential-provider-web-identity": "3.933.0", "@aws-sdk/nested-clients": "3.933.0", "@aws-sdk/types": "3.930.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-HygGyKuMG5AaGXsmM0d81miWDon55xwalRHB3UmDg3QBhtunbNIoIaWUbNTKuBZXcIN6emeeEZw/YgSMqLc0YA=="], + + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.933.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.932.0", "@aws-sdk/credential-provider-http": "3.932.0", "@aws-sdk/credential-provider-ini": "3.933.0", "@aws-sdk/credential-provider-process": "3.932.0", "@aws-sdk/credential-provider-sso": "3.933.0", "@aws-sdk/credential-provider-web-identity": "3.933.0", "@aws-sdk/types": "3.930.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-L2dE0Y7iMLammQewPKNeEh1z/fdJyYEU+/QsLBD9VEh+SXcN/FIyTi21Isw8wPZN6lMB9PDVtISzBnF8HuSFrw=="], + + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.932.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/types": "3.930.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-BodZYKvT4p/Dkm28Ql/FhDdS1+p51bcZeMMu2TRtU8PoMDHnVDhHz27zASEKSZwmhvquxHrZHB0IGuVqjZUtSQ=="], + + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.933.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.933.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/token-providers": "3.933.0", "@aws-sdk/types": "3.930.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/R1DBR7xNcuZIhS2RirU+P2o8E8/fOk+iLAhbqeSTq+g09fP/F6W7ouFpS5eVE2NIfWG7YBFoVddOhvuqpn51g=="], + + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.933.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/nested-clients": "3.933.0", "@aws-sdk/types": "3.930.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-c7Eccw2lhFx2/+qJn3g+uIDWRuWi2A6Sz3PVvckFUEzPsP0dPUo19hlvtarwP5GzrsXn0yEPRVhpewsIaSCGaQ=="], + + "@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-cnCLWeKPYgvV4yRYPFH6pWMdUByvu2cy2BAlfsPpvnm4RaVioztyvxmQj5PmVN5fvWs5w/2d6U7le8X9iye2sA=="], + + "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-5HEQ+JU4DrLNWeY27wKg/jeVa8Suy62ivJHOSUf6e6hZdVIMx0h/kXS1fHEQNNiLu2IzSEP/bFXsKBaW7x7s0g=="], + + "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.932.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/types": "3.930.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-hyvRz/XS/0HTHp9/Ld1mKwpOi7bZu5olI42+T112rkCTbt1bewkygzEl4oflY4H7cKMamQusYoL0yBUD/QSEvA=="], + + "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-x30jmm3TLu7b/b+67nMyoV0NlbnCVT5DI57yDrhXAPCtdgM1KtdLWt45UcHpKOm1JsaIkmYRh2WYu7Anx4MG0g=="], + + "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-QIGNsNUdRICog+LYqmtJ03PLze6h2KCORXUs5td/hAEjVP5DMmubhtrGg1KhWyctACluUH/E/yrD14p4pRXxwA=="], + + "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-vh4JBWzMCBW8wREvAwoSqB2geKsZwSHTa0nSt0OMOLp2PdTYIZDi0ZiVMmpfnjcx9XbS6aSluLv9sKx4RrG46A=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw=="], + "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.933.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-qgrMlkVKzTCAdNw2A05DC2sPBo0KRQ7wk+lbYSRJnWVzcrceJhnmhoZVV5PFv7JtchK7sHVcfm9lcpiyd+XaCA=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww=="], + "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.932.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.2", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-bYMHxqQzseaAP9Z5qLI918z5AtbAnZRRtFi3POb4FLZyreBMgCgBNaPkIhdgywnkqaydTWvbMBX4s9f4gUwlTw=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.782.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/credential-provider-env": "3.775.0", "@aws-sdk/credential-provider-http": "3.775.0", "@aws-sdk/credential-provider-process": "3.775.0", "@aws-sdk/credential-provider-sso": "3.782.0", "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/credential-provider-imds": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw=="], + "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-N2/SvodmaDS6h7CWfuapt3oJyn1T2CBz0CsDIiTDv9cSagXAVFjPdm2g4PFJqrNBeqdDIoYBnnta336HmamWHg=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.782.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.775.0", "@aws-sdk/credential-provider-http": "3.775.0", "@aws-sdk/credential-provider-ini": "3.782.0", "@aws-sdk/credential-provider-process": "3.775.0", "@aws-sdk/credential-provider-sso": "3.782.0", "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/credential-provider-imds": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw=="], + "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.932.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@smithy/core": "^3.18.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9BGTbJyA/4PTdwQWE9hAFIJGpsYkyEW20WON3i15aDqo5oRZwZmqaVageOD57YYqG8JDJjvcwKyDdR4cc38dvg=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg=="], + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.933.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-o1GX0+IPlFi/D8ei9y/jj3yucJWNfPnbB5appVBWevAyUdZA5KzQ2nK/hDxiu9olTZlFEFpf1m1Rn3FaGxHqsw=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.782.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.782.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/token-providers": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ=="], + "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-KL2JZqH6aYeQssu1g1KuWsReupdfOoxD6f1as2VC+rdwYFUu4LfzMsFfXnBvvQWWqQ7rZHWOw1T+o5gJmg7Dzw=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.782.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ=="], + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.932.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.932.0", "@aws-sdk/types": "3.930.0", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-NCIRJvoRc9246RZHIusY1+n/neeG2yGhBGdKhghmrNdM+mLLN6Ii7CKFZjx3DhxtpHMpl1HWLTMhdVrGwP2upw=="], - "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w=="], + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.933.0", "", { "dependencies": { "@aws-sdk/core": "3.932.0", "@aws-sdk/nested-clients": "3.933.0", "@aws-sdk/types": "3.930.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qzq7zj9yXUgAAJEbbmqRhm0jmUndl8nHG0AbxFEfCfQRVZWL96Qzx0mf8lYwT9hIMrXncLwy31HOthmbXwFRwQ=="], - "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw=="], + "@aws-sdk/types": ["@aws-sdk/types@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A=="], - "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA=="], + "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.893.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.782.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@smithy/core": "^3.2.0", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg=="], + "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-M2oEKBzzNAYr136RRc6uqw3aWlwCxqTP1Lawps9E1d2abRPvl1p1ztQmmXp1Ak4rv8eByIZ+yQyKQ3zPdRG5dw=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA=="], + "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.893.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg=="], - "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/types": "^4.2.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.2", "tslib": "^2.6.2" } }, "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ=="], + "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.930.0", "", { "dependencies": { "@aws-sdk/types": "3.930.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-q6lCRm6UAe+e1LguM5E4EqM9brQlDem4XDcQ87NzEvlTW6GzmNCO0w1jS0XgCFXQHjDxjdlNFX+5sRbHijwklg=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.782.0", "", { "dependencies": { "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg=="], + "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.932.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/types": "3.930.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-/kC6cscHrZL74TrZtgiIL5jJNbVsw9duGGPurmaVgoCbP7NnxyaSWEurbNV3VPNPhNE3bV3g4Ci+odq+AlsYQg=="], - "@aws-sdk/types": ["@aws-sdk/types@3.775.0", "", { "dependencies": { "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA=="], + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], - "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.782.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/types": "^4.2.0", "@smithy/util-endpoints": "^3.0.2", "tslib": "^2.6.2" } }, "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw=="], + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.1", "", {}, "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww=="], - "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.804.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A=="], + "@azure/abort-controller": ["@azure/abort-controller@2.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="], - "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/types": "^4.2.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A=="], + "@azure/core-auth": ["@azure/core-auth@1.10.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-util": "^1.13.0", "tslib": "^2.6.2" } }, "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.782.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA=="], + "@azure/core-client": ["@azure/core-client@1.10.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "tslib": "^2.6.2" } }, "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w=="], - "@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], + "@azure/core-http": ["@azure/core-http@3.0.5", "", { "dependencies": { "@azure/abort-controller": "^1.0.0", "@azure/core-auth": "^1.3.0", "@azure/core-tracing": "1.0.0-preview.13", "@azure/core-util": "^1.1.1", "@azure/logger": "^1.0.0", "@types/node-fetch": "^2.5.0", "@types/tunnel": "^0.0.3", "form-data": "^4.0.0", "node-fetch": "^2.6.7", "process": "^0.11.10", "tslib": "^2.2.0", "tunnel": "^0.0.6", "uuid": "^8.3.0", "xml2js": "^0.5.0" } }, "sha512-T8r2q/c3DxNu6mEJfPuJtptUVqwchxzjj32gKcnMi06rdiVONS9rar7kT9T2Am+XvER7uOzpsP79WsqNbdgdWg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="], + "@azure/core-http-compat": ["@azure/core-http-compat@2.3.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g=="], - "@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], + "@azure/core-lro": ["@azure/core-lro@2.7.2", "", { "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", "tslib": "^2.6.2" } }, "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw=="], - "@babel/generator": ["@babel/generator@7.28.0", "", { "dependencies": { "@babel/parser": "^7.28.0", "@babel/types": "^7.28.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg=="], + "@azure/core-paging": ["@azure/core-paging@1.6.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA=="], + + "@azure/core-rest-pipeline": ["@azure/core-rest-pipeline@1.22.2", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg=="], + + "@azure/core-tracing": ["@azure/core-tracing@1.3.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="], + + "@azure/core-util": ["@azure/core-util@1.13.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A=="], + + "@azure/core-xml": ["@azure/core-xml@1.5.0", "", { "dependencies": { "fast-xml-parser": "^5.0.7", "tslib": "^2.8.1" } }, "sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw=="], + + "@azure/logger": ["@azure/logger@1.3.0", "", { "dependencies": { "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA=="], + + "@azure/storage-blob": ["@azure/storage-blob@12.29.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.9.0", "@azure/core-client": "^1.9.3", "@azure/core-http-compat": "^2.2.0", "@azure/core-lro": "^2.2.0", "@azure/core-paging": "^1.6.2", "@azure/core-rest-pipeline": "^1.19.1", "@azure/core-tracing": "^1.2.0", "@azure/core-util": "^1.11.0", "@azure/core-xml": "^1.4.5", "@azure/logger": "^1.1.4", "@azure/storage-common": "^12.1.1", "events": "^3.0.0", "tslib": "^2.8.1" } }, "sha512-7ktyY0rfTM0vo7HvtK6E3UvYnI9qfd6Oz6z/+92VhGRveWng3kJwMKeUpqmW/NmwcDNbxHpSlldG+vsUnRFnBg=="], + + "@azure/storage-common": ["@azure/storage-common@12.1.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.9.0", "@azure/core-http-compat": "^2.2.0", "@azure/core-rest-pipeline": "^1.19.1", "@azure/core-tracing": "^1.2.0", "@azure/core-util": "^1.11.0", "@azure/logger": "^1.1.4", "events": "^3.3.0", "tslib": "^2.8.1" } }, "sha512-eIOH1pqFwI6UmVNnDQvmFeSg0XppuzDLFeUNO/Xht7ODAzRLgGDh7h550pSxoA+lPDxBl1+D2m/KG3jWzCUjTg=="], + + "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], + + "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@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" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="], + + "@babel/generator": ["@babel/generator@7.28.5", "", { "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" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "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" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], - "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg=="], + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="], "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA=="], + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="], + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], @@ -341,13 +764,13 @@ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helpers": ["@babel/helpers@7.28.2", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw=="], + "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="], + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], @@ -355,17 +778,25 @@ "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="], - "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg=="], + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], + + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="], "@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="], - "@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/types": "^7.28.0", "debug": "^4.3.1" } }, "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg=="], + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "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" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], + + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], - "@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="], + "@bufbuild/protobuf": ["@bufbuild/protobuf@2.10.1", "", {}, "sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg=="], + + "@bufbuild/protoplugin": ["@bufbuild/protoplugin@2.10.1", "", { "dependencies": { "@bufbuild/protobuf": "2.10.1", "@typescript/vfs": "^1.6.2", "typescript": "5.4.5" } }, "sha512-imB8dKEjrOnG5+XqVS+CeYn924WGLU/g3wogKhk11XtX9y9NJ7432OS6h24asuBbLrQcPdEZ6QkfM7KeOCeeyQ=="], "@capsizecss/unpack": ["@capsizecss/unpack@2.4.0", "", { "dependencies": { "blob-to-buffer": "^1.2.8", "cross-fetch": "^3.0.4", "fontkit": "^2.0.2" } }, "sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q=="], @@ -375,95 +806,99 @@ "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], - "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.5.0", "", { "peerDependencies": { "unenv": "2.0.0-rc.19", "workerd": "^1.20250722.0" }, "optionalPeers": ["workerd"] }, "sha512-CZe9B2VbjIQjBTyc+KoZcN1oUcm4T6GgCXoel9O7647djHuSRAa6sM6G+NdxWArATZgeMMbsvn9C50GCcnIatA=="], + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.11", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20251106.1" }, "optionalPeers": ["workerd"] }, "sha512-se23f1D4PxKrMKOq+Stz+Yn7AJ9ITHcEecXo2Yjb+UgbUDCEBch1FXQC6hx6uT5fNA3kmX3mfzeZiUmpK1W9IQ=="], - "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250730.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-X3egNyTjLQaECYe34x8Al7r4oXAhcN3a8+8qcpNCcq1sgtuHIeAwS9potgRR/mwkGfmrJn7nfAyDKC4vrkniQQ=="], + "@cloudflare/vite-plugin": ["@cloudflare/vite-plugin@1.15.2", "", { "dependencies": { "@cloudflare/unenv-preset": "2.7.11", "@remix-run/node-fetch-server": "^0.8.0", "get-port": "^7.1.0", "miniflare": "4.20251118.1", "picocolors": "^1.1.1", "tinyglobby": "^0.2.12", "unenv": "2.0.0-rc.24", "wrangler": "4.50.0", "ws": "8.18.0" }, "peerDependencies": { "vite": "^6.1.0 || ^7.0.0" } }, "sha512-SPMxsesbABOjzcAa4IzW+yM+fTIjx3GG1doh229Pg16FjSEZJhknyRpcld4gnaZioK3JKwG9FWdKsUhbplKY8w=="], - "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250730.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/4bvcaGY/9v0rghgKboGiyPKKGQTbDnQ1EeY0oN0SSQH0Cp3OBzqwni/JRvh8TEaD+5azJnSFLlFZj9w7fo+hw=="], + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20251118.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-UmWmYEYS/LkK/4HFKN6xf3Hk8cw70PviR+ftr3hUvs9HYZS92IseZEp16pkL6ZBETrPRpZC7OrzoYF7ky6kHsg=="], - "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250730.0", "", { "os": "linux", "cpu": "x64" }, "sha512-I4ZsXYdNkqkJnzNFKADMufiLIzRdIRsN7dSH8UCPw2fYp1BbKA10AkKVqitFwBxIY8eOzQ6Vf7c41AjLQmtJqA=="], + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20251118.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RockU7Qzf4rxNfY1lx3j4rvwutNLjTIX7rr2hogbQ4mzLo8Ea40/oZTzXVxl+on75joLBrt0YpenGW8o/r44QA=="], - "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250730.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-tTpO6139jFQ5vxgtBZgS8Y8R1jVidS4n7s37x5xO9bCWLZoL0kTj38UGZ8FENkTeaMxE9Mm//nbQol7TfJ2nZg=="], + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20251118.0", "", { "os": "linux", "cpu": "x64" }, "sha512-aT97GnOAbJDuuOG0zPVhgRk0xFtB1dzBMrxMZ09eubDLoU4djH4BuORaqvxNRMmHgKfa4T6drthckT0NjUvBdw=="], - "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250730.0", "", { "os": "win32", "cpu": "x64" }, "sha512-paVHgocuilMzOU+gEyKR/86j/yI+QzmSHRnqdd8OdQ37Hf6SyPX7kQj6VVNRXbzVHWix1WxaJsXfTGK1LK05wA=="], + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20251118.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-bXZPJcwlq00MPOXqP7DMWjr+goYj0+Fqyw6zgEC2M3FR1+SWla4yjghnZ4IdpN+H1t7VbUrsi5np2LzMUFs0NA=="], - "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250522.0", "", {}, "sha512-9RIffHobc35JWeddzBguGgPa4wLDr5x5F94+0/qy7LiV6pTBQ/M5qGEN9VA16IDT3EUpYI0WKh6VpcmeVEtVtw=="], + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20251118.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2LV99AHSlpr8WcCb/BYbU2QsYkXLUL1izN6YKWkN9Eibv80JKX0RtgmD3dfmajE5sNvClavxZejgzVvHD9N9Ag=="], - "@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="], + "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20251008.0", "", {}, "sha512-dZLkO4PbCL0qcCSKzuW7KE4GYe49lI12LCfQ5y9XeSwgYBoAUbwH4gmJ6A0qUIURiTJTkGkRkhVPqpq2XNgYRA=="], "@corvu/utils": ["@corvu/utils@0.4.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.11" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA=="], "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], - "@ctrl/tinycolor": ["@ctrl/tinycolor@4.1.0", "", {}, "sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ=="], + "@ctrl/tinycolor": ["@ctrl/tinycolor@4.2.0", "", {}, "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A=="], + + "@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="], - "@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="], + "@dot/log": ["@dot/log@0.1.5", "", { "dependencies": { "chalk": "^4.1.2", "loglevelnext": "^6.0.0", "p-defer": "^3.0.0" } }, "sha512-ECraEVJWv2f2mWK93lYiefUkphStVlKD6yKDzisuoEmxuLKrxO9iGetHK2DoEAkj7sxjE886n0OUVVCUx0YPNg=="], - "@deno/shim-deno": ["@deno/shim-deno@0.19.2", "", { "dependencies": { "@deno/shim-deno-test": "^0.5.0", "which": "^4.0.0" } }, "sha512-q3VTHl44ad8T2Tw2SpeAvghdGOjlnLPDNO2cpOxwMrBE/PVas6geWpbpIgrM+czOCH0yejp0yi8OaTuB+NU40Q=="], + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], - "@deno/shim-deno-test": ["@deno/shim-deno-test@0.5.0", "", {}, "sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w=="], + "@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], - "@dependents/detective-less": ["@dependents/detective-less@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], - "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="], + "@emotion/is-prop-valid": ["@emotion/is-prop-valid@0.8.8", "", { "dependencies": { "@emotion/memoize": "0.7.4" } }, "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA=="], + + "@emotion/memoize": ["@emotion/memoize@0.7.4", "", {}, "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="], "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.8", "", { "os": "aix", "cpu": "ppc64" }, "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.8", "", { "os": "android", "cpu": "arm" }, "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.8", "", { "os": "android", "cpu": "arm64" }, "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.8", "", { "os": "android", "cpu": "x64" }, "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.8", "", { "os": "linux", "cpu": "arm" }, "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.8", "", { "os": "linux", "cpu": "ia32" }, "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.8", "", { "os": "linux", "cpu": "x64" }, "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.8", "", { "os": "none", "cpu": "x64" }, "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.8", "", { "os": "sunos", "cpu": "x64" }, "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], "@expressive-code/core": ["@expressive-code/core@0.41.3", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-9qzohqU7O0+JwMEEgQhnBPOw5DtsQRBXhW++5fvEywsuX44vCGGof1SL5OvPElvNgaWZ4pFZAFSlkNOkGyLwSQ=="], @@ -473,29 +908,41 @@ "@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3" } }, "sha512-SN8tkIzDpA0HLAscEYD2IVrfLiid6qEdE9QLlGVSxO1KEw7qYvjpbNBQjUjMr5/jvTJ7ys6zysU2vLPHE0sb2g=="], - "@fastify/busboy": ["@fastify/busboy@3.1.1", "", {}, "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw=="], + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], - "@floating-ui/dom": ["@floating-ui/dom@1.7.3", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag=="], + "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="], "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], "@fontsource/ibm-plex-mono": ["@fontsource/ibm-plex-mono@5.2.5", "", {}, "sha512-G09N3GfuT9qj3Ax2FDZvKqZttzM3v+cco2l8uXamhKyXLdmlaUDH5o88/C3vtTHj2oT7yRKsvxz9F+BXbWKMYA=="], - "@grpc/grpc-js": ["@grpc/grpc-js@1.13.4", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg=="], + "@fontsource/inter": ["@fontsource/inter@5.2.8", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="], + + "@gitlab/gitlab-ai-provider": ["@gitlab/gitlab-ai-provider@3.1.3", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=2.0.0", "@ai-sdk/provider-utils": ">=3.0.0" } }, "sha512-ikumi4PZN/S0f+j/5rb5dBRtORyT41Pl/tj8vHhnpFtpYcxXsaNv2RvCKBVf2/PovvSz2pYMOcpujIU4MdGfyQ=="], + + "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], + + "@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.0.11", "", { "dependencies": { "@types/node": "^20.0.0", "happy-dom": "^20.0.11" } }, "sha512-GqNqiShBT/lzkHTMC/slKBrvN0DsD4Di8ssBk4aDaVgEn+2WMzE6DXxq701ndSXj7/0cJ8mNT71pM7Bnrr6JRw=="], + + "@hey-api/codegen-core": ["@hey-api/codegen-core@0.5.2", "", { "dependencies": { "ansi-colors": "4.1.3", "color-support": "1.1.3" }, "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-88cqrrB2cLXN8nMOHidQTcVOnZsJ5kebEbBefjMCifaUCwTA30ouSSWvTZqrOX4O104zjJyu7M8Gcv/NNYQuaA=="], - "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], + "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.2.2", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.1", "lodash": "^4.17.21" } }, "sha512-oS+5yAdwnK20lSeFO1d53Ku+yaGCsY8PcrmSq2GtSs3bsBfRnHAbpPKSVzQcaxAOrzj5NB+f34WhZglVrNayBA=="], - "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.0.6", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0", "lodash": "^4.17.21" } }, "sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w=="], + "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.90.4", "", { "dependencies": { "@hey-api/codegen-core": "^0.5.2", "@hey-api/json-schema-ref-parser": "1.2.2", "ansi-colors": "4.1.3", "c12": "3.3.3", "color-support": "1.1.3", "commander": "14.0.2", "open": "11.0.0", "semver": "7.7.3" }, "peerDependencies": { "typescript": ">=5.5.3" }, "bin": { "openapi-ts": "bin/run.js" } }, "sha512-9l++kjcb0ui4JqPlueZ6OZ9zKn6eK/8//Z2jHcIXb5MRwDRgubOOSpTU5llEv3uvWfT10VzcMp99dySWq0AASw=="], - "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.80.1", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-AC478kg36vmmrseLZNFonZ/cmXXmDzW5yWz4PVg1S8ebJsRtVRJ/QU+mtnXfzf9avN2P0pz/AO4WAe4jyFY2gA=="], + "@hono/node-server": ["@hono/node-server@1.19.7", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw=="], + + "@hono/standard-validator": ["@hono/standard-validator@0.1.5", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-EIyZPPwkyLn6XKwFj5NBEWHXhXbgmnVh2ceIFo5GO7gKI9WmzTjPDKnppQB0KrqKeAkq3kpoW4SIbu5X1dgx3w=="], "@hono/zod-validator": ["@hono/zod-validator@0.4.2", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-1rrlBg+EpDPhzOV4hT9pxr5+xDVmKuz6YJl+la7VCwK6ass5ldyKm5fD+umJdV2zhHD6jROoCCv8NbTwyfhT0g=="], "@ibm/plex": ["@ibm/plex@6.4.1", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.1" } }, "sha512-fnsipQywHt3zWvsnlyYKMikcVI7E2fEwpiPnIHFqlbByXVfQfANAAeJk1IV4mNnxhppUIDlhU0TzwYwL++Rn2g=="], - "@ibm/telemetry-js": ["@ibm/telemetry-js@1.9.1", "", { "bin": { "ibmtelemetry": "dist/collect.js" } }, "sha512-qq8RPafUJHUQieXVCte1kbJEx6JctWzbA/YkXzopbfzIDRT2+hbR9QmgH+KH7bDDNRcDbdHWvHfwJKzThlMtPg=="], + "@ibm/telemetry-js": ["@ibm/telemetry-js@1.10.2", "", { "bin": { "ibmtelemetry": "dist/collect.js" } }, "sha512-F8+/NNUwtm8BuFz18O9KPvIFTFDo8GUSoyhPxPjEpk7nEyEzWGfhIiEPhL00B2NdHRLDSljh3AiCfSnL/tutiQ=="], "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], @@ -535,11 +982,11 @@ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], - "@internationalized/date": ["@internationalized/date@3.8.2", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA=="], + "@internationalized/date": ["@internationalized/date@3.10.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw=="], - "@internationalized/number": ["@internationalized/number@3.6.4", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-P+/h+RDaiX8EGt3shB9AYM1+QgkvHmJ5rKi4/59k4sg9g58k9rqsRW0WxRO7jCoHyvVbFRRFKmVTdFYdehrxHg=="], + "@internationalized/number": ["@internationalized/number@3.6.5", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g=="], - "@ioredis/commands": ["@ioredis/commands@1.3.0", "", {}, "sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ=="], + "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], @@ -549,593 +996,927 @@ "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - "@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], + "@jimp/core": ["@jimp/core@1.6.0", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="], + "@jimp/diff": ["@jimp/diff@1.6.0", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="], - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + "@jimp/file-ops": ["@jimp/file-ops@1.6.0", "", {}, "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ=="], - "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], + "@jimp/js-bmp": ["@jimp/js-bmp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "bmp-ts": "^1.0.9" } }, "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="], + "@jimp/js-gif": ["@jimp/js-gif@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "jpeg-js": "^0.4.4" } }, "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA=="], - "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + "@jimp/js-png": ["@jimp/js-png@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "pngjs": "^7.0.0" } }, "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg=="], - "@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="], + "@jimp/js-tiff": ["@jimp/js-tiff@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "utif2": "^4.1.0" } }, "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw=="], - "@kobalte/core": ["@kobalte/core@0.13.9", "", { "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" } }, "sha512-TkeSpgNy7I5k8jwjqT9CK3teAxN0aFb3yyL9ODb06JVYMwXIk+UKrizoAF1ahLUP85lKnxv44B4Y5cXkHShgqw=="], + "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA=="], - "@kobalte/utils": ["@kobalte/utils@0.9.1", "", { "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" } }, "sha512-eeU60A3kprIiBDAfv9gUJX1tXGLuZiKMajUfSQURAF2pk4ZoMYiqIzmrMBvzcxP39xnYttgTyQEVLwiTZnrV4w=="], + "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw=="], - "@logdna/tail-file": ["@logdna/tail-file@2.2.0", "", {}, "sha512-XGSsWDweP80Fks16lwkAUIr54ICyBs6PsI4mpfTLQaWgEJRtY9xEV+PeyDpJ+sJEGZxqINlpmAwe/6tS1pP8Ng=="], + "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw=="], - "@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.0", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg=="], + "@jimp/plugin-color": ["@jimp/plugin-color@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA=="], - "@mdx-js/mdx": ["@mdx-js/mdx@3.1.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw=="], + "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ=="], - "@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="], + "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA=="], - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.15.1", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-W/XlN9c528yYn+9MQkVjxiTPgPxoxt+oczfjHBDsJx0+59+O7B75Zhsp0B16Xbwbz8ANISDajh6+V7nIcPMc5w=="], + "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang=="], - "@netlify/binary-info": ["@netlify/binary-info@1.0.0", "", {}, "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw=="], + "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q=="], - "@netlify/blobs": ["@netlify/blobs@9.1.2", "", { "dependencies": { "@netlify/dev-utils": "2.2.0", "@netlify/runtime-utils": "1.3.1" } }, "sha512-7dMjExSH4zj4ShvLem49mE3mf0K171Tx2pV4WDWhJbRUWW3SJIR2qntz0LvUGS97N5HO1SmnzrgWUhEXCsApiw=="], + "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0" } }, "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ=="], - "@netlify/dev-utils": ["@netlify/dev-utils@2.2.0", "", { "dependencies": { "@whatwg-node/server": "^0.9.60", "chokidar": "^4.0.1", "decache": "^4.6.2", "dot-prop": "9.0.0", "env-paths": "^3.0.0", "find-up": "7.0.0", "lodash.debounce": "^4.0.8", "netlify": "^13.3.5", "parse-gitignore": "^2.0.0", "uuid": "^11.1.0", "write-file-atomic": "^6.0.0" } }, "sha512-5XUvZuffe3KetyhbWwd4n2ktd7wraocCYw10tlM+/u/95iAz29GjNiuNxbCD1T6Bn1MyGc4QLVNKOWhzJkVFAw=="], + "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA=="], - "@netlify/functions": ["@netlify/functions@3.1.10", "", { "dependencies": { "@netlify/blobs": "9.1.2", "@netlify/dev-utils": "2.2.0", "@netlify/serverless-functions-api": "1.41.2", "@netlify/zip-it-and-ship-it": "^12.1.0", "cron-parser": "^4.9.0", "decache": "^4.6.2", "extract-zip": "^2.0.1", "is-stream": "^4.0.1", "jwt-decode": "^4.0.0", "lambda-local": "^2.2.0", "read-package-up": "^11.0.0", "source-map-support": "^0.5.21" } }, "sha512-sI93kcJ2cUoMgDRPnrEm0lZhuiDVDqM6ngS/UbHTApIH3+eg3yZM5p/0SDFQQq9Bad0/srFmgBmTdXushzY5kg=="], + "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg=="], - "@netlify/open-api": ["@netlify/open-api@2.37.0", "", {}, "sha512-zXnRFkxgNsalSgU8/vwTWnav3R+8KG8SsqHxqaoJdjjJtnZR7wo3f+qqu4z+WtZ/4V7fly91HFUwZ6Uz2OdW7w=="], + "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "any-base": "^1.1.0" } }, "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q=="], - "@netlify/runtime-utils": ["@netlify/runtime-utils@1.3.1", "", {}, "sha512-7/vIJlMYrPJPlEW84V2yeRuG3QBu66dmlv9neTmZ5nXzwylhBEOhy11ai+34A8mHCSZI4mKns25w3HM9kaDdJg=="], + "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA=="], - "@netlify/serverless-functions-api": ["@netlify/serverless-functions-api@1.41.2", "", {}, "sha512-pfCkH50JV06SGMNsNPjn8t17hOcId4fA881HeYQgMBOrewjsw4csaYgHEnCxCEu24Y5x75E2ULbFpqm9CvRCqw=="], + "@jimp/plugin-print": ["@jimp/plugin-print@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/types": "1.6.0", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A=="], - "@netlify/zip-it-and-ship-it": ["@netlify/zip-it-and-ship-it@12.2.1", "", { "dependencies": { "@babel/parser": "^7.22.5", "@babel/types": "7.28.0", "@netlify/binary-info": "^1.0.0", "@netlify/serverless-functions-api": "^2.1.3", "@vercel/nft": "0.29.4", "archiver": "^7.0.0", "common-path-prefix": "^3.0.0", "copy-file": "^11.0.0", "es-module-lexer": "^1.0.0", "esbuild": "0.25.5", "execa": "^8.0.0", "fast-glob": "^3.3.3", "filter-obj": "^6.0.0", "find-up": "^7.0.0", "is-builtin-module": "^3.1.0", "is-path-inside": "^4.0.0", "junk": "^4.0.0", "locate-path": "^7.0.0", "merge-options": "^3.0.4", "minimatch": "^9.0.0", "normalize-path": "^3.0.0", "p-map": "^7.0.0", "path-exists": "^5.0.0", "precinct": "^12.0.0", "require-package-name": "^2.0.1", "resolve": "^2.0.0-next.1", "semver": "^7.3.8", "tmp-promise": "^3.0.2", "toml": "^3.0.0", "unixify": "^1.0.0", "urlpattern-polyfill": "8.0.2", "yargs": "^17.0.0", "zod": "^3.23.8" }, "bin": { "zip-it-and-ship-it": "./bin.js" } }, "sha512-zAr+8Tg80y/sUbhdUkZsq4Uy1IMzkSB6H/sKRMrDQ2NJx4uPgf5X5jMdg9g2FljNcxzpfJwc1Gg4OXQrjD0Z4A=="], + "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.0", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg=="], - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA=="], - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw=="], - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w=="], - "@npmcli/agent": ["@npmcli/agent@2.2.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og=="], + "@jimp/types": ["@jimp/types@1.6.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg=="], - "@npmcli/arborist": ["@npmcli/arborist@7.5.4", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^3.1.1", "@npmcli/installed-package-contents": "^2.1.0", "@npmcli/map-workspaces": "^3.0.2", "@npmcli/metavuln-calculator": "^7.1.1", "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.1.0", "@npmcli/query": "^3.1.0", "@npmcli/redact": "^2.0.0", "@npmcli/run-script": "^8.1.0", "bin-links": "^4.0.4", "cacache": "^18.0.3", "common-ancestor-path": "^1.0.1", "hosted-git-info": "^7.0.2", "json-parse-even-better-errors": "^3.0.2", "json-stringify-nice": "^1.1.4", "lru-cache": "^10.2.2", "minimatch": "^9.0.4", "nopt": "^7.2.1", "npm-install-checks": "^6.2.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.1", "npm-registry-fetch": "^17.0.1", "pacote": "^18.0.6", "parse-conflict-json": "^3.0.0", "proc-log": "^4.2.0", "proggy": "^2.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "ssri": "^10.0.6", "treeverse": "^3.0.0", "walk-up-path": "^3.0.1" }, "bin": { "arborist": "bin/index.js" } }, "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g=="], + "@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="], - "@npmcli/fs": ["@npmcli/fs@3.1.1", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - "@npmcli/git": ["@npmcli/git@5.0.8", "", { "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^4.0.0" } }, "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ=="], + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - "@npmcli/installed-package-contents": ["@npmcli/installed-package-contents@2.1.0", "", { "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" }, "bin": { "installed-package-contents": "bin/index.js" } }, "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w=="], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@npmcli/map-workspaces": ["@npmcli/map-workspaces@3.0.6", "", { "dependencies": { "@npmcli/name-from-folder": "^2.0.0", "glob": "^10.2.2", "minimatch": "^9.0.0", "read-package-json-fast": "^3.0.0" } }, "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA=="], + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], - "@npmcli/metavuln-calculator": ["@npmcli/metavuln-calculator@7.1.1", "", { "dependencies": { "cacache": "^18.0.0", "json-parse-even-better-errors": "^3.0.0", "pacote": "^18.0.0", "proc-log": "^4.1.0", "semver": "^7.3.5" } }, "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@npmcli/name-from-folder": ["@npmcli/name-from-folder@2.0.0", "", {}, "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@npmcli/node-gyp": ["@npmcli/node-gyp@3.0.0", "", {}, "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA=="], + "@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="], - "@npmcli/package-json": ["@npmcli/package-json@5.2.1", "", { "dependencies": { "@npmcli/git": "^5.0.0", "glob": "^10.2.2", "hosted-git-info": "^7.0.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^6.0.0", "proc-log": "^4.0.0", "semver": "^7.5.3" } }, "sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ=="], + "@jsx-email/all": ["@jsx-email/all@2.2.3", "", { "dependencies": { "@jsx-email/body": "1.0.2", "@jsx-email/button": "1.0.4", "@jsx-email/column": "1.0.3", "@jsx-email/container": "1.0.2", "@jsx-email/font": "1.0.3", "@jsx-email/head": "1.0.2", "@jsx-email/heading": "1.0.2", "@jsx-email/hr": "1.0.2", "@jsx-email/html": "1.0.2", "@jsx-email/img": "1.0.2", "@jsx-email/link": "1.0.2", "@jsx-email/markdown": "2.0.4", "@jsx-email/preview": "1.0.2", "@jsx-email/render": "1.1.1", "@jsx-email/row": "1.0.2", "@jsx-email/section": "1.0.2", "@jsx-email/tailwind": "2.4.4", "@jsx-email/text": "1.0.2" }, "peerDependencies": { "react": "^18.2.0" } }, "sha512-OBvLe/hVSQc0LlMSTJnkjFoqs3bmxcC4zpy/5pT5agPCSKMvAKQjzmsc2xJ2wO73jSpRV1K/g38GmvdCfrhSoQ=="], - "@npmcli/promise-spawn": ["@npmcli/promise-spawn@7.0.2", "", { "dependencies": { "which": "^4.0.0" } }, "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ=="], + "@jsx-email/body": ["@jsx-email/body@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-NjR2tgLH4XGfGkm+O8kcVwi9MBqZsXZCLlmk3HlMux3/n/+a5zB+yhJqXWZBJl2i+6cSF+E2O6hK11ekyK9WWQ=="], - "@npmcli/query": ["@npmcli/query@3.1.0", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" } }, "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ=="], + "@jsx-email/button": ["@jsx-email/button@1.0.4", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-NbuxtBtTdcFOKpyw166lvgA8sKpgwQzqpRVSTDZdd+2xlh5gzeckXG9VtCbfktIatD26r45ZMmP68QGK3hxIPA=="], - "@npmcli/redact": ["@npmcli/redact@2.0.1", "", {}, "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw=="], + "@jsx-email/cli": ["@jsx-email/cli@1.4.3", "", { "dependencies": { "@dot/log": "^0.1.3", "@fontsource/inter": "^5.0.8", "@jsx-email/doiuse-email": "^1.0.1", "@jsx-email/render": "1.1.1", "@radix-ui/colors": "1.0.1", "@radix-ui/react-collapsible": "1.0.3", "@radix-ui/react-popover": "1.0.6", "@radix-ui/react-slot": "1.0.2", "@radix-ui/react-toggle-group": "1.0.4", "@radix-ui/react-tooltip": "1.0.6", "@vitejs/plugin-react": "^4.1.0", "autoprefixer": "^10.4.16", "chalk": "4.1.2", "cheerio": "1.0.0-rc.12", "classnames": "2.3.2", "debug": "^4.3.4", "esbuild": "^0.19.3", "esbuild-plugin-copy": "^2.1.1", "framer-motion": "8.5.5", "globby": "11.0.4", "html-minifier-terser": "^7.2.0", "import-local": "^3.1.0", "js-beautify": "^1.14.9", "mustache": "^4.2.0", "postcss": "^8.4.30", "react": "18.2.0", "react-dom": "18.2.0", "react-router-dom": "6.16.0", "shikiji": "^0.6.8", "superstruct": "^1.0.3", "tailwindcss": "3.3.3", "titleize": "^4.0.0", "vite": "^4.4.9", "vite-plugin-dynamic-import": "^1.5.0", "yargs-parser": "^21.1.1" }, "bin": { "email": "dist/src/index.js" } }, "sha512-Aid5d5U3RM9sjkjzn/X/a5FFWLJSXlwh8pagBVgnUTiaBM8+nroSPZaC21Xe3rl/uwYpY9lc+2AAH9+7SmroiQ=="], - "@npmcli/run-script": ["@npmcli/run-script@8.1.0", "", { "dependencies": { "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.0.0", "@npmcli/promise-spawn": "^7.0.0", "node-gyp": "^10.0.0", "proc-log": "^4.0.0", "which": "^4.0.0" } }, "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg=="], + "@jsx-email/column": ["@jsx-email/column@1.0.3", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-dto5s/INVWy4oMOETX53O53NerpPxezO8CQctriTaHLrqlR22lWoXJZoGTzMvt9uLyoUrYViA6Tj2F9Bio+fOg=="], - "@octokit/auth-app": ["@octokit/auth-app@8.0.1", "", { "dependencies": { "@octokit/auth-oauth-app": "^9.0.1", "@octokit/auth-oauth-user": "^6.0.0", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" } }, "sha512-P2J5pB3pjiGwtJX4WqJVYCtNkcZ+j5T2Wm14aJAEIC3WJOrv12jvBley3G1U/XI8q9o1A7QMG54LiFED2BiFlg=="], + "@jsx-email/container": ["@jsx-email/container@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-Muue8X2PgjxCf+YvUJ6zGTqcmo3i4S3EmsLGYpnWl7e/ZKmMLTjN4DdUeSsi27fWEdpUTjQQG4McMGdFYhZTGg=="], - "@octokit/auth-oauth-app": ["@octokit/auth-oauth-app@9.0.1", "", { "dependencies": { "@octokit/auth-oauth-device": "^8.0.1", "@octokit/auth-oauth-user": "^6.0.0", "@octokit/request": "^10.0.2", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-TthWzYxuHKLAbmxdFZwFlmwVyvynpyPmjwc+2/cI3cvbT7mHtsAW9b1LvQaNnAuWL+pFnqtxdmrU8QpF633i1g=="], + "@jsx-email/doiuse-email": ["@jsx-email/doiuse-email@1.0.4", "", { "dependencies": { "@adobe/css-tools": "^4.3.1", "css-what": "^6.1.0", "domhandler": "^5.0.3", "dot-prop": "^8.0.2", "htmlparser2": "^9.0.0", "micromatch": "^4.0.5", "style-to-object": "^1.0.4" } }, "sha512-HfLjuQsAAyAkIZWR0wHR6+P6u40RIX0jBZu/1rgsw18+jc36agZD5j84zG4CDzitRxgXJXrAohPfDFPxcrtjAA=="], - "@octokit/auth-oauth-device": ["@octokit/auth-oauth-device@8.0.1", "", { "dependencies": { "@octokit/oauth-methods": "^6.0.0", "@octokit/request": "^10.0.2", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-TOqId/+am5yk9zor0RGibmlqn4V0h8vzjxlw/wYr3qzkQxl8aBPur384D1EyHtqvfz0syeXji4OUvKkHvxk/Gw=="], + "@jsx-email/font": ["@jsx-email/font@1.0.3", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-NRp9NBjrmYVwAFYRwuifzvavtHB8blRLEJ+q9BygY3y58+FhHENweU8FMdC5OSts2C99FbKrHUicTSanEj8+Aw=="], - "@octokit/auth-oauth-user": ["@octokit/auth-oauth-user@6.0.0", "", { "dependencies": { "@octokit/auth-oauth-device": "^8.0.1", "@octokit/oauth-methods": "^6.0.0", "@octokit/request": "^10.0.2", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-GV9IW134PHsLhtUad21WIeP9mlJ+QNpFd6V9vuPWmaiN25HEJeEQUcS4y5oRuqCm9iWDLtfIs+9K8uczBXKr6A=="], + "@jsx-email/head": ["@jsx-email/head@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-M5Af6Imt7W/Vp09dY76I/v7gRe1aQLmeXjBZZSrSbvpMVQVAd6gwR/druNaAO+zHDoKhXwR50+pxXpnC+TFiIw=="], - "@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], + "@jsx-email/heading": ["@jsx-email/heading@1.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "react": "^18.2.0" } }, "sha512-yumw176gsAJQnwSx0HCamCj2DozQireayax7s+jvr+TvEvFxNLD4PQvK45c6JdYYD9OPGnjDApks102FJQ7xDQ=="], - "@octokit/core": ["@octokit/core@7.0.3", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.1", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ=="], + "@jsx-email/hr": ["@jsx-email/hr@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-CuJ/ADJoRwuQyUqulOf00BceTdY9kzrLQTMwGPUmFMtlsF+EFSPNULoksFg6nskVjFV7pBUm78FwiEfP2OAHMQ=="], - "@octokit/endpoint": ["@octokit/endpoint@11.0.0", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ=="], + "@jsx-email/html": ["@jsx-email/html@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-FOiJdZWbCwNwsAqRuXlrXo39UTVWtrezuzA0pXY0UD5nEPzwpk7N46EwW8uxBRoqNRPiuUnwnFWLXuPZNAIGlg=="], - "@octokit/graphql": ["@octokit/graphql@9.0.1", "", { "dependencies": { "@octokit/request": "^10.0.2", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg=="], + "@jsx-email/img": ["@jsx-email/img@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-aqqnx43Cvq/wVzALhK6n5pSJBqTRwq5wuM66/QAkEJaZgXqrXCNRx1fNeqQt/Zp2j6KmHq3Ax0AHSJX4pjKIDw=="], - "@octokit/oauth-authorization-url": ["@octokit/oauth-authorization-url@8.0.0", "", {}, "sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ=="], + "@jsx-email/link": ["@jsx-email/link@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-+mr+WFHZ7fILkFlSdbusSm9ml6jPq7u89LGe2E71AB23JEaaF8qO5u6so6wySAme+gDIGId/+tobPcTHeI+hHQ=="], - "@octokit/oauth-methods": ["@octokit/oauth-methods@6.0.0", "", { "dependencies": { "@octokit/oauth-authorization-url": "^8.0.0", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0" } }, "sha512-Q8nFIagNLIZgM2odAraelMcDssapc+lF+y3OlcIPxyAU+knefO8KmozGqfnma1xegRDP4z5M73ABsamn72bOcA=="], + "@jsx-email/markdown": ["@jsx-email/markdown@2.0.4", "", { "dependencies": { "md-to-react-email": "5.0.0" }, "peerDependencies": { "react": "^18.2.0" } }, "sha512-jYf/BVGKjz7TU1FhEX0ELZGKPQj+6o0R4NjZTBJsJ3PUovgXynS4GqU83eARwGbOSUve/9qvRljsCCQHD+t/Gg=="], - "@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + "@jsx-email/preview": ["@jsx-email/preview@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-dkc3hG08R0J0TEQ/cDCtdyoLYddb1MIvhh5OyTqfd5pgSxPF6MaSH8LkDqMUYpSYZ3RtUK6g4d8q3mF7tx28sQ=="], - "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.1.1", "", { "dependencies": { "@octokit/types": "^14.1.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw=="], + "@jsx-email/render": ["@jsx-email/render@1.1.1", "", { "dependencies": { "html-to-text": "9.0.5", "pretty": "2.0.0" } }, "sha512-0y45YofM0Ak8Rswss1AWgy7v9mlMoHMrgD0x601gvb2HBddDp2r0etNJhhN9ZwW8QOteuYluHD279e+PCr2WxA=="], - "@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], + "@jsx-email/row": ["@jsx-email/row@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-6bUr1rqIsUVrhBWcTj0QTZvUQ/deThDKoi10dSfhjmbUqFYr7RdyGwMwsUuFg1YzZCohvy8dVpBIwd+5wmtsIw=="], - "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@16.0.0", "", { "dependencies": { "@octokit/types": "^14.1.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g=="], + "@jsx-email/section": ["@jsx-email/section@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-gGGE9zkljfrgWOz7NlmFsDPVKCQv6omu+VXsce0yh0+yHBehuFYrv4WOqMZFtfQo6Y1IDdQWt+XCi5GlEvd0Lw=="], - "@octokit/request": ["@octokit/request@10.0.3", "", { "dependencies": { "@octokit/endpoint": "^11.0.0", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA=="], + "@jsx-email/tailwind": ["@jsx-email/tailwind@2.4.4", "", { "dependencies": { "@jsx-email/render": "1.1.1", "react": "18.2.0", "react-dom": "18.2.0", "tw-to-css": "0.0.12" } }, "sha512-RqLD0y2le1ruFBt9MCa0PNnTVUgcS8vcOOWMJUkMezBZUAUkP5KSj3DO+6DdgVn67kH9cnnRvknXo8L6qd6BwA=="], - "@octokit/request-error": ["@octokit/request-error@7.0.0", "", { "dependencies": { "@octokit/types": "^14.0.0" } }, "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg=="], + "@jsx-email/text": ["@jsx-email/text@1.0.2", "", { "peerDependencies": { "react": "^18.2.0" } }, "sha512-0zzwEwrKtY6tfjPJF0r3krKCDpP/ySYDvkn4+MvIFrIH5RZKmn3XDa5o/3hkbxMwpLn4MsXGIXn9XzMTaqTfUA=="], - "@octokit/rest": ["@octokit/rest@22.0.0", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="], + "@kobalte/core": ["@kobalte/core@0.13.11", "", { "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" } }, "sha512-hK7TYpdib/XDb/r/4XDBFaO9O+3ZHz4ZWryV4/3BfES+tSQVgg2IJupDnztKXB0BqbSRy/aWlHKw1SPtNPYCFQ=="], - "@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + "@kobalte/utils": ["@kobalte/utils@0.9.1", "", { "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" } }, "sha512-eeU60A3kprIiBDAfv9gUJX1tXGLuZiKMajUfSQURAF2pk4ZoMYiqIzmrMBvzcxP39xnYttgTyQEVLwiTZnrV4w=="], - "@octokit/webhooks-types": ["@octokit/webhooks-types@7.6.1", "", {}, "sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw=="], + "@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="], - "@openauthjs/openauth": ["@openauthjs/openauth@0.0.0-20250322224806", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-p5IWSRXvABcwocH2dNI0w8c1QJelIOFulwhKk+aLLFfUbs8u1pr7kQbYe8yCSM2+bcLHiwbogpUQc2ovrGwCuw=="], + "@leichtgewicht/ip-codec": ["@leichtgewicht/ip-codec@2.0.5", "", {}, "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="], - "@openauthjs/solid": ["@openauthjs/solid@0.0.0-20250322224806", "", { "dependencies": { "@openauthjs/openauth": "0.4.2", "@solid-primitives/storage": "^4.3.1" }, "peerDependencies": { "solid-js": "^1.8.0" } }, "sha512-ln/yZQ/i+2vkrVSDOxxmbC8Oq6P2sljtdCiiAPZXj8etihwT11CYtj4jsrwArQltog738N2uvd2dKpHopVqLSQ=="], + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@workspace:packages/plugin"], + "@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.2", "", { "dependencies": { "@hono/node-server": "^1.19.7", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww=="], - "@opencode/cloud-app": ["@opencode/cloud-app@workspace:cloud/app"], + "@motionone/animation": ["@motionone/animation@10.18.0", "", { "dependencies": { "@motionone/easing": "^10.18.0", "@motionone/types": "^10.17.1", "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" } }, "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw=="], - "@opencode/cloud-core": ["@opencode/cloud-core@workspace:cloud/core"], + "@motionone/dom": ["@motionone/dom@10.18.0", "", { "dependencies": { "@motionone/animation": "^10.18.0", "@motionone/generators": "^10.18.0", "@motionone/types": "^10.17.1", "@motionone/utils": "^10.18.0", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A=="], - "@opencode/cloud-function": ["@opencode/cloud-function@workspace:cloud/function"], + "@motionone/easing": ["@motionone/easing@10.18.0", "", { "dependencies": { "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" } }, "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg=="], - "@opencode/cloud-web": ["@opencode/cloud-web@workspace:cloud/web"], + "@motionone/generators": ["@motionone/generators@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" } }, "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg=="], - "@opencode/function": ["@opencode/function@workspace:packages/function"], + "@motionone/types": ["@motionone/types@10.17.1", "", {}, "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A=="], - "@opencode/web": ["@opencode/web@workspace:packages/web"], + "@motionone/utils": ["@motionone/utils@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw=="], - "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], - "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.55.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@1.30.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA=="], + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - "@opentelemetry/core": ["@opentelemetry/core@1.30.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ=="], + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@opentelemetry/exporter-zipkin": ["@opentelemetry/exporter-zipkin@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1", "@opentelemetry/sdk-trace-base": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" } }, "sha512-6S2QIMJahIquvFaaxmcwpvQQRD/YFaMTNoIxrfPIPOeITN+a8lfEcPDxNxn8JDAaxkg+4EnXhz8upVDYenoQjA=="], + "@octokit/auth-app": ["@octokit/auth-app@8.0.1", "", { "dependencies": { "@octokit/auth-oauth-app": "^9.0.1", "@octokit/auth-oauth-user": "^6.0.0", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" } }, "sha512-P2J5pB3pjiGwtJX4WqJVYCtNkcZ+j5T2Wm14aJAEIC3WJOrv12jvBley3G1U/XI8q9o1A7QMG54LiFED2BiFlg=="], - "@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.55.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.55.0", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "semver": "^7.5.2", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-YDCMlaQRZkziLL3t6TONRgmmGxDx6MyQDXRD0dknkkgUZtOK5+8MWft1OXzmNu6XfBOdT12MKN5rz+jHUkafKQ=="], + "@octokit/auth-oauth-app": ["@octokit/auth-oauth-app@9.0.3", "", { "dependencies": { "@octokit/auth-oauth-device": "^8.0.3", "@octokit/auth-oauth-user": "^6.0.2", "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-+yoFQquaF8OxJSxTb7rnytBIC2ZLbLqA/yb71I4ZXT9+Slw4TziV9j/kyGhUFRRTF2+7WlnIWsePZCWHs+OGjg=="], - "@opentelemetry/instrumentation-grpc": ["@opentelemetry/instrumentation-grpc@0.55.0", "", { "dependencies": { "@opentelemetry/instrumentation": "0.55.0", "@opentelemetry/semantic-conventions": "1.27.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-n2ZH4pRwOy0Vhag/3eKqiyDBwcpUnGgJI9iiIRX7vivE0FMncaLazWphNFezRRaM/LuKwq1TD8pVUvieP68mow=="], + "@octokit/auth-oauth-device": ["@octokit/auth-oauth-device@8.0.3", "", { "dependencies": { "@octokit/oauth-methods": "^6.0.2", "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-zh2W0mKKMh/VWZhSqlaCzY7qFyrgd9oTWmTmHaXnHNeQRCZr/CXy2jCgHo4e4dJVTiuxP5dLa0YM5p5QVhJHbw=="], - "@opentelemetry/propagator-b3": ["@opentelemetry/propagator-b3@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-oATwWWDIJzybAZ4pO76ATN5N6FFbOA1otibAVlS8v90B4S1wClnhRUk7K+2CHAwN1JKYuj4jh/lpCEG5BAqFuQ=="], + "@octokit/auth-oauth-user": ["@octokit/auth-oauth-user@6.0.2", "", { "dependencies": { "@octokit/auth-oauth-device": "^8.0.3", "@octokit/oauth-methods": "^6.0.2", "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-qLoPPc6E6GJoz3XeDG/pnDhJpTkODTGG4kY0/Py154i/I003O9NazkrwJwRuzgCalhzyIeWQ+6MDvkUmKXjg/A=="], - "@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Pj/BfnYEKIOImirH76M4hDaBSx6HyZ2CXUqk+Kj02m6BB80c/yo4BdWkn/1gDFfU+YPY+bPR2U0DKBfdxCKwmg=="], + "@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="], - "@opentelemetry/resources": ["@opentelemetry/resources@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA=="], + "@octokit/core": ["@octokit/core@5.2.2", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="], - "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg=="], + "@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="], - "@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@1.30.1", "", { "dependencies": { "@opentelemetry/context-async-hooks": "1.30.1", "@opentelemetry/core": "1.30.1", "@opentelemetry/propagator-b3": "1.30.1", "@opentelemetry/propagator-jaeger": "1.30.1", "@opentelemetry/sdk-trace-base": "1.30.1", "semver": "^7.5.2" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-cBjYOINt1JxXdpw1e5MlHmFRc5fgj4GW/86vsKFxJCJ8AL4PdVtYH41gWwl4qd4uQjqEL1oJVrXkSy5cnduAnQ=="], + "@octokit/graphql": ["@octokit/graphql@9.0.2", "", { "dependencies": { "@octokit/request": "^10.0.4", "@octokit/types": "^15.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw=="], - "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="], + "@octokit/oauth-authorization-url": ["@octokit/oauth-authorization-url@8.0.0", "", {}, "sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ=="], - "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], + "@octokit/oauth-methods": ["@octokit/oauth-methods@6.0.2", "", { "dependencies": { "@octokit/oauth-authorization-url": "^8.0.0", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0" } }, "sha512-HiNOO3MqLxlt5Da5bZbLV8Zarnphi4y9XehrbaFMkcoJ+FL7sMxH/UlUsCVxpddVu4qvNDrBdaTVE2o4ITK8ng=="], - "@oslojs/binary": ["@oslojs/binary@1.0.0", "", {}, "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ=="], + "@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], - "@oslojs/crypto": ["@oslojs/crypto@1.0.1", "", { "dependencies": { "@oslojs/asn1": "1.0.0", "@oslojs/binary": "1.0.0" } }, "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ=="], + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.2.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw=="], - "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="], + "@octokit/plugin-request-log": ["@octokit/plugin-request-log@1.0.4", "", { "peerDependencies": { "@octokit/core": ">=3" } }, "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA=="], - "@oslojs/jwt": ["@oslojs/jwt@0.2.0", "", { "dependencies": { "@oslojs/encoding": "0.4.1" } }, "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg=="], + "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@16.1.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg=="], - "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A=="], + "@octokit/plugin-retry": ["@octokit/plugin-retry@3.0.9", "", { "dependencies": { "@octokit/types": "^6.0.3", "bottleneck": "^2.15.3" } }, "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ=="], - "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-zlGHA23uuXmS8z3XxEGmbHpWDxXfPZ47QS06tGUq0HDcZjXjXHeLG+cboOy828QIV5FXsm9MjfkP5e4ZNbOkow=="], + "@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="], - "@pagefind/default-ui": ["@pagefind/default-ui@1.3.0", "", {}, "sha512-CGKT9ccd3+oRK6STXGgfH+m0DbOKayX6QGlq38TfE1ZfUcPc5+ulTuzDbZUnMo+bubsEOIypm4Pl2iEyzZ1cNg=="], + "@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="], - "@pagefind/linux-arm64": ["@pagefind/linux-arm64@1.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-8lsxNAiBRUk72JvetSBXs4WRpYrQrVJXjlRRnOL6UCdBN9Nlsz0t7hWstRk36+JqHpGWOKYiuHLzGYqYAqoOnQ=="], + "@octokit/rest": ["@octokit/rest@22.0.0", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="], - "@pagefind/linux-x64": ["@pagefind/linux-x64@1.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-hAvqdPJv7A20Ucb6FQGE6jhjqy+vZ6pf+s2tFMNtMBG+fzcdc91uTw7aP/1Vo5plD0dAOHwdxfkyw0ugal4kcQ=="], + "@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], - "@pagefind/windows-x64": ["@pagefind/windows-x64@1.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-BR1bIRWOMqkf8IoU576YDhij1Wd/Zf2kX/kCI0b2qzCKC8wcc2GQJaaRMCpzvCCrmliO4vtJ6RITp/AnoYUUmQ=="], + "@octokit/webhooks-types": ["@octokit/webhooks-types@7.6.1", "", {}, "sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw=="], - "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], + "@one-ini/wasm": ["@one-ini/wasm@0.1.1", "", {}, "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="], - "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], + "@openauthjs/openauth": ["@openauthjs/openauth@0.0.0-20250322224806", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-p5IWSRXvABcwocH2dNI0w8c1QJelIOFulwhKk+aLLFfUbs8u1pr7kQbYe8yCSM2+bcLHiwbogpUQc2ovrGwCuw=="], - "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], + "@opencode-ai/app": ["@opencode-ai/app@workspace:packages/app"], - "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], + "@opencode-ai/console-app": ["@opencode-ai/console-app@workspace:packages/console/app"], - "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], + "@opencode-ai/console-core": ["@opencode-ai/console-core@workspace:packages/console/core"], - "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], + "@opencode-ai/console-function": ["@opencode-ai/console-function@workspace:packages/console/function"], - "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], + "@opencode-ai/console-mail": ["@opencode-ai/console-mail@workspace:packages/console/mail"], - "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], + "@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"], - "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], + "@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"], - "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], + "@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"], - "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], + "@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"], - "@parcel/watcher-wasm": ["@parcel/watcher-wasm@2.3.0", "", { "dependencies": { "is-glob": "^4.0.3", "micromatch": "^4.0.5", "napi-wasm": "^1.1.0" } }, "sha512-ejBAX8H0ZGsD8lSICDNyMbSEtPMWgDL0WFCt/0z7hyf5v8Imz4rAM8xY379mBsECkq/Wdqa5WEDLqtjZ+6NxfA=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@workspace:packages/plugin"], - "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], + "@opencode-ai/script": ["@opencode-ai/script@workspace:packages/script"], - "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"], - "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], + "@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"], - "@petamoriken/float16": ["@petamoriken/float16@3.9.2", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="], + "@opencode-ai/ui": ["@opencode-ai/ui@workspace:packages/ui"], - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + "@opencode-ai/util": ["@opencode-ai/util@workspace:packages/util"], - "@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="], + "@opencode-ai/web": ["@opencode-ai/web@workspace:packages/web"], - "@poppinss/dumper": ["@poppinss/dumper@0.6.4", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ=="], + "@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@1.5.2", "", { "dependencies": { "@openrouter/sdk": "^0.1.27" }, "peerDependencies": { "@toon-format/toon": "^2.0.0", "ai": "^5.0.0", "zod": "^3.24.1 || ^v4" }, "optionalPeers": ["@toon-format/toon"] }, "sha512-3Th0vmJ9pjnwcPc2H1f59Mb0LFvwaREZAScfOQIpUxAHjZ7ZawVKDP27qgsteZPmMYqccNMy4r4Y3kgUnNcKAg=="], - "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="], + "@openrouter/sdk": ["@openrouter/sdk@0.1.27", "", { "dependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-RH//L10bSmc81q25zAZudiI4kNkLgxF2E+WU42vghp3N6TEvZ6F0jK7uT3tOxkEn91gzmMw9YVmDENy7SJsajQ=="], - "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + "@opentui/core": ["@opentui/core@0.1.74", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.74", "@opentui/core-darwin-x64": "0.1.74", "@opentui/core-linux-arm64": "0.1.74", "@opentui/core-linux-x64": "0.1.74", "@opentui/core-win32-arm64": "0.1.74", "@opentui/core-win32-x64": "0.1.74", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-g4W16ymv12JdgZ+9B4t7mpIICvzWy2+eHERfmDf80ALduOQCUedKQdULcBFhVCYUXIkDRtIy6CID5thMAah3FA=="], - "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.74", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rfmlDLtm/u17CnuhJgCxPeYMvOST+A2MOdVOk46IurtHO849bdYqK6iudKNlFRs1FOrymgSKF9GlWBHAOKeRjg=="], - "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.74", "", { "os": "darwin", "cpu": "x64" }, "sha512-WAD8orsDV0ZdW/5GwjOOB4FY96772xbkz+rcV7WRzEFUVaqoBaC04IuqYzS9d5s+cjkbT5Cpj47hrVYkkVQKng=="], - "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.74", "", { "os": "linux", "cpu": "arm64" }, "sha512-lgmHzrzLy4e+rgBS+lhtsMLLgIMLbtLNMm6EzVPyYVDlLDGjM7+ulXMem7AtpaRrWrUUl4REiG9BoQUsCFDwYA=="], - "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.74", "", { "os": "linux", "cpu": "x64" }, "sha512-8Mn2WbdBQ29xCThuPZezjDhd1N3+fXwKkGvCBOdTI0le6h2A/vCNbfUVjwfr/EGZSRXxCG+Yapol34BAULGpOA=="], - "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.74", "", { "os": "win32", "cpu": "arm64" }, "sha512-dvYUXz03avnI6ZluyLp00HPmR0UT/IE/6QS97XBsgJlUTtpnbKkBtB5jD1NHwWkElaRj1Qv2QP36ngFoJqbl9g=="], - "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.74", "", { "os": "win32", "cpu": "x64" }, "sha512-3wfWXaAKOIlDQz6ZZIESf2M+YGZ7uFHijjTEM8w/STRlLw8Y6+QyGYi1myHSM4d6RSO+/s2EMDxvjDf899W9vQ=="], - "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + "@opentui/solid": ["@opentui/solid@0.1.74", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.74", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-Vz82cI8T9YeJjGsVg4ULp6ral4N+xyt1j9A6Tbu3aaQgEKiB74LW03EXREehfjPr1irOFxtKfWPbx5NKH0Upag=="], - "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], - "@pulumi/pulumi": ["@pulumi/pulumi@3.188.0", "", { "dependencies": { "@grpc/grpc-js": "^1.10.1", "@logdna/tail-file": "^2.0.6", "@npmcli/arborist": "^7.3.1", "@opentelemetry/api": "^1.9", "@opentelemetry/exporter-zipkin": "^1.28", "@opentelemetry/instrumentation": "^0.55", "@opentelemetry/instrumentation-grpc": "^0.55", "@opentelemetry/resources": "^1.28", "@opentelemetry/sdk-trace-base": "^1.28", "@opentelemetry/sdk-trace-node": "^1.28", "@types/google-protobuf": "^3.15.5", "@types/semver": "^7.5.6", "@types/tmp": "^0.2.6", "execa": "^5.1.0", "fdir": "^6.1.1", "google-protobuf": "^3.5.0", "got": "^11.8.6", "ini": "^2.0.0", "js-yaml": "^3.14.0", "minimist": "^1.2.6", "normalize-package-data": "^6.0.0", "picomatch": "^3.0.1", "pkg-dir": "^7.0.0", "require-from-string": "^2.0.1", "semver": "^7.5.2", "source-map-support": "^0.5.6", "tmp": "^0.2.4", "upath": "^1.1.0" }, "peerDependencies": { "ts-node": ">= 7.0.1 < 12", "typescript": ">= 3.8.3 < 6" }, "optionalPeers": ["ts-node", "typescript"] }, "sha512-c2L2QMq1bNo+1TxuoMQKQM7fiIZOMAAjDaIr2JKyg/ADGi7dhpKckEDbg43EMlzFUtI7t0mkiUYTaVPVcZ1kqg=="], + "@oslojs/binary": ["@oslojs/binary@1.0.0", "", {}, "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ=="], - "@rollup/plugin-alias": ["@rollup/plugin-alias@5.1.1", "", { "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ=="], + "@oslojs/crypto": ["@oslojs/crypto@1.0.1", "", { "dependencies": { "@oslojs/asn1": "1.0.0", "@oslojs/binary": "1.0.0" } }, "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ=="], - "@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@28.0.6", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw=="], + "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="], - "@rollup/plugin-inject": ["@rollup/plugin-inject@5.0.5", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "estree-walker": "^2.0.2", "magic-string": "^0.30.3" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg=="], + "@oslojs/jwt": ["@oslojs/jwt@0.2.0", "", { "dependencies": { "@oslojs/encoding": "0.4.1" } }, "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg=="], - "@rollup/plugin-json": ["@rollup/plugin-json@6.1.0", "", { "dependencies": { "@rollup/pluginutils": "^5.1.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA=="], + "@oxc-minify/binding-android-arm64": ["@oxc-minify/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lzeIEMu/v6Y+La5JSesq4hvyKtKBq84cgQpKYTYM/yGuNk2tfd5Ha31hnC+mTh48lp/5vZH+WBfjVUjjINCfug=="], - "@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA=="], + "@oxc-minify/binding-darwin-arm64": ["@oxc-minify/binding-darwin-arm64@0.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-i0LkJAUXb4BeBFrJQbMKQPoxf8+cFEffDyLSb7NEzzKuPcH8qrVsnEItoOzeAdYam8Sr6qCHVwmBNEQzl7PWpw=="], - "@rollup/plugin-replace": ["@rollup/plugin-replace@6.0.2", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "magic-string": "^0.30.3" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ=="], + "@oxc-minify/binding-darwin-x64": ["@oxc-minify/binding-darwin-x64@0.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-C5vI0WPR+KPIFAD5LMOJk2J8iiT+Nv65vDXmemzXEXouzfEOLYNqnW+u6NSsccpuZHHWAiLyPFkYvKFduveAUQ=="], - "@rollup/plugin-terser": ["@rollup/plugin-terser@0.4.4", "", { "dependencies": { "serialize-javascript": "^6.0.1", "smob": "^1.0.0", "terser": "^5.17.4" }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A=="], + "@oxc-minify/binding-freebsd-x64": ["@oxc-minify/binding-freebsd-x64@0.96.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-3//5DNx+xUjVBMLLk2sl6hfe4fwfENJtjVQUBXjxzwPuv8xgZUqASG4cRG3WqG5Qe8dV6SbCI4EgKQFjO4KCZA=="], - "@rollup/pluginutils": ["@rollup/pluginutils@5.2.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw=="], + "@oxc-minify/binding-linux-arm-gnueabihf": ["@oxc-minify/binding-linux-arm-gnueabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-WXChFKV7VdDk1NePDK1J31cpSvxACAVztJ7f7lJVYBTkH+iz5D0lCqPcE7a9eb7nC3xvz4yk7DM6dA9wlUQkQg=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.2", "", { "os": "android", "cpu": "arm" }, "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA=="], + "@oxc-minify/binding-linux-arm-musleabihf": ["@oxc-minify/binding-linux-arm-musleabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-7B18glYMX4Z/YoqgE3VRLs/2YhVLxlxNKSgrtsRpuR8xv58xca+hEhiFwZN1Rn+NSMZ29Z33LWD7iYWnqYFvRA=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.46.2", "", { "os": "android", "cpu": "arm64" }, "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ=="], + "@oxc-minify/binding-linux-arm64-gnu": ["@oxc-minify/binding-linux-arm64-gnu@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Yl+KcTldsEJNcaYxxonwAXZ2q3gxIzn3kXYQWgKWdaGIpNhOCWqF+KE5WLsldoh5Ro5SHtomvb8GM6cXrIBMog=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.46.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ=="], + "@oxc-minify/binding-linux-arm64-musl": ["@oxc-minify/binding-linux-arm64-musl@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-rNqoFWOWaxwMmUY5fspd/h5HfvgUlA3sv9CUdA2MpnHFiyoJNovR7WU8tGh+Yn0qOAs0SNH0a05gIthHig14IA=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.46.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA=="], + "@oxc-minify/binding-linux-riscv64-gnu": ["@oxc-minify/binding-linux-riscv64-gnu@0.96.0", "", { "os": "linux", "cpu": "none" }, "sha512-3paajIuzGnukHwSI3YBjYVqbd72pZd8NJxaayaNFR0AByIm8rmIT5RqFXbq8j2uhtpmNdZRXiu0em1zOmIScWA=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.46.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg=="], + "@oxc-minify/binding-linux-s390x-gnu": ["@oxc-minify/binding-linux-s390x-gnu@0.96.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-9ESrpkB2XG0lQ89JlsxlZa86iQCOs+jkDZLl6O+u5wb7ynUy21bpJJ1joauCOSYIOUlSy3+LbtJLiqi7oSQt5Q=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.46.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw=="], + "@oxc-minify/binding-linux-x64-gnu": ["@oxc-minify/binding-linux-x64-gnu@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-UMM1jkns+p+WwwmdjC5giI3SfR2BCTga18x3C0cAu6vDVf4W37uTZeTtSIGmwatTBbgiq++Te24/DE0oCdm1iQ=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.46.2", "", { "os": "linux", "cpu": "arm" }, "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA=="], + "@oxc-minify/binding-linux-x64-musl": ["@oxc-minify/binding-linux-x64-musl@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8b1naiC7MdP7xeMi7cQ5tb9W1rZAP9Qz/jBRqp1Y5EOZ1yhSGnf1QWuZ/0pCc+XiB9vEHXEY3Aki/H+86m2eOg=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.46.2", "", { "os": "linux", "cpu": "arm" }, "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ=="], + "@oxc-minify/binding-wasm32-wasi": ["@oxc-minify/binding-wasm32-wasi@0.96.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-bjGDjkGzo3GWU9Vg2qiFUrfoo5QxojPNV/2RHTlbIB5FWkkV4ExVjsfyqihFiAuj0NXIZqd2SAiEq9htVd3RFw=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.46.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng=="], + "@oxc-minify/binding-win32-arm64-msvc": ["@oxc-minify/binding-win32-arm64-msvc@0.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-4L4DlHUT47qMWQuTyUghpncR3NZHWtxvd0G1KgSjVgXf+cXzFdWQCWZZtCU0yrmOoVCNUf4S04IFCJyAe+Ie7A=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.46.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg=="], + "@oxc-minify/binding-win32-x64-msvc": ["@oxc-minify/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-T2ijfqZLpV2bgGGocXV4SXTuMoouqN0asYTIm+7jVOLvT5XgDogf3ZvCmiEnSWmxl21+r5wHcs8voU2iUROXAg=="], - "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA=="], + "@oxc-transform/binding-android-arm64": ["@oxc-transform/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-wOm+ZsqFvyZ7B9RefUMsj0zcXw77Z2pXA51nbSQyPXqr+g0/pDGxriZWP8Sdpz/e4AEaKPA9DvrwyOZxu7GRDQ=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.46.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw=="], + "@oxc-transform/binding-darwin-arm64": ["@oxc-transform/binding-darwin-arm64@0.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-td1sbcvzsyuoNRiNdIRodPXRtFFwxzPpC/6/yIUtRRhKn30XQcizxupIvQQVpJWWchxkphbBDh6UN+u+2CJ8Zw=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ=="], + "@oxc-transform/binding-darwin-x64": ["@oxc-transform/binding-darwin-x64@0.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xgqxnqhPYH2NYkgbqtnCJfhbXvxIf/pnhF/ig5UBK8PYpCEWIP/cfLpQRQ9DcQnRfuxi7RMIF6LdmB1AiS6Fkg=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw=="], + "@oxc-transform/binding-freebsd-x64": ["@oxc-transform/binding-freebsd-x64@0.96.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1i67OXdl/rvSkcTXqDlh6qGRXYseEmf0rl/R+/i88scZ/o3A+FzlX56sThuaPzSSv9eVgesnoYUjIBJELFc1oA=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.46.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA=="], + "@oxc-transform/binding-linux-arm-gnueabihf": ["@oxc-transform/binding-linux-arm-gnueabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-9MJBs0SWODsqyzO3eAnacXgJ/sZu1xqinjEwBzkcZ3tQI8nKhMADOzu2NzbVWDWujeoC8DESXaO08tujvUru+Q=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.46.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA=="], + "@oxc-transform/binding-linux-arm-musleabihf": ["@oxc-transform/binding-linux-arm-musleabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-BQom57I2ScccixljNYh2Wy+5oVZtF1LXiiUPxSLtDHbsanpEvV/+kzCagQpTjk1BVzSQzOxfEUWjvL7mY53pRQ=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.46.2", "", { "os": "linux", "cpu": "x64" }, "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA=="], + "@oxc-transform/binding-linux-arm64-gnu": ["@oxc-transform/binding-linux-arm64-gnu@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-kaqvUzNu8LL4aBSXqcqGVLFG13GmJEplRI2+yqzkgAItxoP/LfFMdEIErlTWLGyBwd0OLiNMHrOvkcCQRWadVg=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.46.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g=="], + "@oxc-transform/binding-linux-arm64-musl": ["@oxc-transform/binding-linux-arm64-musl@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EiG/L3wEkPgTm4p906ufptyblBgtiQWTubGg/JEw82f8uLRroayr5zhbUqx40EgH037a3SfJthIyLZi7XPRFJw=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.46.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ=="], + "@oxc-transform/binding-linux-riscv64-gnu": ["@oxc-transform/binding-linux-riscv64-gnu@0.96.0", "", { "os": "linux", "cpu": "none" }, "sha512-r01CY6OxKGtVeYnvH4mGmtkQMlLkXdPWWNXwo5o7fE2s/fgZPMpqh8bAuXEhuMXipZRJrjxTk1+ZQ4KCHpMn3Q=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.46.2", "", { "os": "win32", "cpu": "x64" }, "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg=="], + "@oxc-transform/binding-linux-s390x-gnu": ["@oxc-transform/binding-linux-s390x-gnu@0.96.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-4djg2vYLGbVeS8YiA2K4RPPpZE4fxTGCX5g/bOMbCYyirDbmBAIop4eOAj8vOA9i1CcWbDtmp+PVJ1dSw7f3IQ=="], - "@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], + "@oxc-transform/binding-linux-x64-gnu": ["@oxc-transform/binding-linux-x64-gnu@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-f6pcWVz57Y8jXa2OS7cz3aRNuks34Q3j61+3nQ4xTE8H1KbalcEvHNmM92OEddaJ8QLs9YcE0kUC6eDTbY34+A=="], - "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-1/adJbSMBOkpScCE/SB6XkjJU17ANln3Wky7lOmrnpl+zBdQ1qXUJg2GXTYVHRq+2j3hd1DesmElTXYDgtfSOQ=="], + "@oxc-transform/binding-linux-x64-musl": ["@oxc-transform/binding-linux-x64-musl@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-NSiRtFvR7Pbhv3mWyPMkTK38czIjcnK0+K5STo3CuzZRVbX1TM17zGdHzKBUHZu7v6IQ6/XsQ3ELa1BlEHPGWQ=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-zcZKMnNndgRa3ORja6Iemsr3DrLtkX3cAF7lTJkdMB6v9alhlBsX9uNiCpqofNrXOvpA3h6lHcLJxgCIhVOU5Q=="], + "@oxc-transform/binding-wasm32-wasi": ["@oxc-transform/binding-wasm32-wasi@0.96.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-A91ARLiuZHGN4hBds9s7bW3czUuLuHLsV+cz44iF9j8e1zX9m2hNGXf/acQRbg/zcFUXmjz5nmk8EkZyob876w=="], - "@shikijs/langs": ["@shikijs/langs@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2" } }, "sha512-H6azIAM+OXD98yztIfs/KH5H4PU39t+SREhmM8LaNXyUrqj2mx+zVkr8MWYqjceSjDw9I1jawm1WdFqU806rMA=="], + "@oxc-transform/binding-win32-arm64-msvc": ["@oxc-transform/binding-win32-arm64-msvc@0.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-IedJf40djKgDObomhYjdRAlmSYUEdfqX3A3M9KfUltl9AghTBBLkTzUMA7O09oo71vYf5TEhbFM7+Vn5vqw7AQ=="], - "@shikijs/themes": ["@shikijs/themes@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2" } }, "sha512-qAEuAQh+brd8Jyej2UDDf+b4V2g1Rm8aBIdvt32XhDPrHvDkEnpb7Kzc9hSuHUxz0Iuflmq7elaDuQAP9bHIhg=="], + "@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="], - "@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], + "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.4.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ=="], - "@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], + "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.4.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A=="], - "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + "@pagefind/default-ui": ["@pagefind/default-ui@1.4.0", "", {}, "sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ=="], - "@sigstore/bundle": ["@sigstore/bundle@2.3.2", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.3.2" } }, "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA=="], + "@pagefind/freebsd-x64": ["@pagefind/freebsd-x64@1.4.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q=="], - "@sigstore/core": ["@sigstore/core@1.1.0", "", {}, "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg=="], + "@pagefind/linux-arm64": ["@pagefind/linux-arm64@1.4.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw=="], - "@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.3.3", "", {}, "sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ=="], + "@pagefind/linux-x64": ["@pagefind/linux-x64@1.4.0", "", { "os": "linux", "cpu": "x64" }, "sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg=="], - "@sigstore/sign": ["@sigstore/sign@2.3.2", "", { "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", "@sigstore/protobuf-specs": "^0.3.2", "make-fetch-happen": "^13.0.1", "proc-log": "^4.2.0", "promise-retry": "^2.0.1" } }, "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA=="], + "@pagefind/windows-x64": ["@pagefind/windows-x64@1.4.0", "", { "os": "win32", "cpu": "x64" }, "sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g=="], - "@sigstore/tuf": ["@sigstore/tuf@2.3.4", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.3.2", "tuf-js": "^2.2.1" } }, "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw=="], + "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], - "@sigstore/verify": ["@sigstore/verify@1.2.1", "", { "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.1.0", "@sigstore/protobuf-specs": "^0.3.2" } }, "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g=="], + "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], - "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], - "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="], + "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], - "@smithy/abort-controller": ["@smithy/abort-controller@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-jcrqdTQurIrBbUm4W2YdLVMQDoL0sA9DTxYd2s+R/y+2U9NLOP7Xf/YqfSg1FZhlZIYEnvk2mwbyvIfdLEPo8g=="], + "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], - "@smithy/config-resolver": ["@smithy/config-resolver@4.1.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.1.4", "@smithy/types": "^4.3.2", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.5", "tslib": "^2.6.2" } }, "sha512-viuHMxBAqydkB0AfWwHIdwf/PRH2z5KHGUzqyRtS/Wv+n3IHI993Sk76VCA7dD/+GzgGOmlJDITfPcJC1nIVIw=="], + "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], - "@smithy/core": ["@smithy/core@3.8.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.9", "@smithy/protocol-http": "^5.1.3", "@smithy/types": "^4.3.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.5", "@smithy/util-stream": "^4.2.4", "@smithy/util-utf8": "^4.0.0", "@types/uuid": "^9.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" } }, "sha512-EYqsIYJmkR1VhVE9pccnk353xhs+lB6btdutJEtsp7R055haMJp2yE16eSxw8fv+G0WUY6vqxyYOP8kOqawxYQ=="], + "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], - "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.0.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.1.4", "@smithy/property-provider": "^4.0.5", "@smithy/types": "^4.3.2", "@smithy/url-parser": "^4.0.5", "tslib": "^2.6.2" } }, "sha512-dDzrMXA8d8riFNiPvytxn0mNwR4B3h8lgrQ5UjAGu6T9z/kRg/Xncf4tEQHE/+t25sY8IH3CowcmWi+1U5B1Gw=="], + "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], - "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.0.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig=="], + "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], - "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.1.1", "", { "dependencies": { "@smithy/protocol-http": "^5.1.3", "@smithy/querystring-builder": "^4.0.5", "@smithy/types": "^4.3.2", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-61WjM0PWmZJR+SnmzaKI7t7G0UkkNFboDpzIdzSoy7TByUzlxo18Qlh9s71qug4AY4hlH/CwXdubMtkcNEb/sQ=="], + "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], - "@smithy/hash-node": ["@smithy/hash-node@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-cv1HHkKhpyRb6ahD8Vcfb2Hgz67vNIXEp2vnhzfxLFGRukLCNEA5QdsorbUEzXma1Rco0u3rx5VTqbM06GcZqQ=="], + "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], - "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-IVnb78Qtf7EJpoEVo7qJ8BEXQwgC4n3igeJNNKEj/MLYtapnx8A67Zt/J3RXAj2xSO1910zk0LdFiygSemuLow=="], + "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], - "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="], + "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], - "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.0.5", "", { "dependencies": { "@smithy/protocol-http": "^5.1.3", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-l1jlNZoYzoCC7p0zCtBDE5OBXZ95yMKlRlftooE5jPWQn4YBPLgsp+oeHp7iMHaTGoUdFqmHOPa8c9G3gBsRpQ=="], + "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], - "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.1.18", "", { "dependencies": { "@smithy/core": "^3.8.0", "@smithy/middleware-serde": "^4.0.9", "@smithy/node-config-provider": "^4.1.4", "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.3.2", "@smithy/url-parser": "^4.0.5", "@smithy/util-middleware": "^4.0.5", "tslib": "^2.6.2" } }, "sha512-ZhvqcVRPZxnZlokcPaTwb+r+h4yOIOCJmx0v2d1bpVlmP465g3qpVSf7wxcq5zZdu4jb0H4yIMxuPwDJSQc3MQ=="], + "@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="], - "@smithy/middleware-retry": ["@smithy/middleware-retry@4.1.19", "", { "dependencies": { "@smithy/node-config-provider": "^4.1.4", "@smithy/protocol-http": "^5.1.3", "@smithy/service-error-classification": "^4.0.7", "@smithy/smithy-client": "^4.4.10", "@smithy/types": "^4.3.2", "@smithy/util-middleware": "^4.0.5", "@smithy/util-retry": "^4.0.7", "@types/uuid": "^9.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" } }, "sha512-X58zx/NVECjeuUB6A8HBu4bhx72EoUz+T5jTMIyeNKx2lf+Gs9TmWPNNkH+5QF0COjpInP/xSpJGJ7xEnAklQQ=="], + "@pierre/diffs": ["@pierre/diffs@1.0.2", "", { "dependencies": { "@shikijs/core": "^3.0.0", "@shikijs/engine-javascript": "3.19.0", "@shikijs/transformers": "3.19.0", "diff": "8.0.2", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "3.19.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-RkFSDD5X/U+8QjyilPViYGJfmJNWXR17zTL8zw48+DcVC1Ujbh6I1edyuRnFfgRzpft05x2DSCkz2cjoIAxPvQ=="], - "@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.9", "", { "dependencies": { "@smithy/protocol-http": "^5.1.3", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-uAFFR4dpeoJPGz8x9mhxp+RPjo5wW0QEEIPPPbLXiRRWeCATf/Km3gKIVR5vaP8bN1kgsPhcEeh+IZvUlBv6Xg=="], + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - "@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-/yoHDXZPh3ocRVyeWQFvC44u8seu3eYzZRveCMfgMOBcNKnAmOvjbL9+Cp5XKSIi9iYA9PECUuW2teDAk8T+OQ=="], + "@planetscale/database": ["@planetscale/database@1.19.0", "", {}, "sha512-Tv4jcFUFAFjOWrGSio49H6R2ijALv0ZzVBfJKIdm+kl9X046Fh4LLawrF9OMsglVbK6ukqMJsUCeucGAFTBcMA=="], - "@smithy/node-config-provider": ["@smithy/node-config-provider@4.1.4", "", { "dependencies": { "@smithy/property-provider": "^4.0.5", "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-+UDQV/k42jLEPPHSn39l0Bmc4sB1xtdI9Gd47fzo/0PbXzJ7ylgaOByVjF5EeQIumkepnrJyfx86dPa9p47Y+w=="], + "@playwright/test": ["@playwright/test@1.57.0", "", { "dependencies": { "playwright": "1.57.0" }, "bin": { "playwright": "cli.js" } }, "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.1.1", "", { "dependencies": { "@smithy/abort-controller": "^4.0.5", "@smithy/protocol-http": "^5.1.3", "@smithy/querystring-builder": "^4.0.5", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-RHnlHqFpoVdjSPPiYy/t40Zovf3BBHc2oemgD7VsVTFFZrU5erFFe0n52OANZZ/5sbshgD93sOh5r6I35Xmpaw=="], + "@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="], - "@smithy/property-provider": ["@smithy/property-provider@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-R/bswf59T/n9ZgfgUICAZoWYKBHcsVDurAGX88zsiUtOTA/xUAPyiT+qkNCPwFn43pZqN84M4MiUsbSGQmgFIQ=="], + "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], - "@smithy/protocol-http": ["@smithy/protocol-http@5.1.3", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-fCJd2ZR7D22XhDY0l+92pUag/7je2BztPRQ01gU5bMChcyI0rlly7QFibnYHzcxDvccMjlpM/Q1ev8ceRIb48w=="], + "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="], - "@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-NJeSCU57piZ56c+/wY+AbAw6rxCCAOZLCIniRE7wqvndqxcKKDOXzwWjrY7wGKEISfhL9gBbAaWWgHsUGedk+A=="], + "@protobuf-ts/plugin": ["@protobuf-ts/plugin@2.11.1", "", { "dependencies": { "@bufbuild/protobuf": "^2.4.0", "@bufbuild/protoplugin": "^2.4.0", "@protobuf-ts/protoc": "^2.11.1", "@protobuf-ts/runtime": "^2.11.1", "@protobuf-ts/runtime-rpc": "^2.11.1", "typescript": "^3.9" }, "bin": { "protoc-gen-ts": "bin/protoc-gen-ts", "protoc-gen-dump": "bin/protoc-gen-dump" } }, "sha512-HyuprDcw0bEEJqkOWe1rnXUP0gwYLij8YhPuZyZk6cJbIgc/Q0IFgoHQxOXNIXAcXM4Sbehh6kjVnCzasElw1A=="], - "@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-6SV7md2CzNG/WUeTjVe6Dj8noH32r4MnUeFKZrnVYsQxpGSIcphAanQMayi8jJLZAWm6pdM9ZXvKCpWOsIGg0w=="], + "@protobuf-ts/protoc": ["@protobuf-ts/protoc@2.11.1", "", { "bin": { "protoc": "protoc.js" } }, "sha512-mUZJaV0daGO6HUX90o/atzQ6A7bbN2RSuHtdwo8SSF2Qoe3zHwa4IHyCN1evftTeHfLmdz+45qo47sL+5P8nyg=="], - "@smithy/service-error-classification": ["@smithy/service-error-classification@4.0.7", "", { "dependencies": { "@smithy/types": "^4.3.2" } }, "sha512-XvRHOipqpwNhEjDf2L5gJowZEm5nsxC16pAZOeEcsygdjv9A2jdOh3YoDQvOXBGTsaJk6mNWtzWalOB9976Wlg=="], + "@protobuf-ts/runtime": ["@protobuf-ts/runtime@2.11.1", "", {}, "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ=="], - "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-YVVwehRDuehgoXdEL4r1tAAzdaDgaC9EQvhK0lEbfnbrd0bd5+CTQumbdPryX3J2shT7ZqQE+jPW4lmNBAB8JQ=="], + "@protobuf-ts/runtime-rpc": ["@protobuf-ts/runtime-rpc@2.11.1", "", { "dependencies": { "@protobuf-ts/runtime": "^2.11.1" } }, "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ=="], - "@smithy/signature-v4": ["@smithy/signature-v4@5.1.3", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "@smithy/protocol-http": "^5.1.3", "@smithy/types": "^4.3.2", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-middleware": "^4.0.5", "@smithy/util-uri-escape": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-mARDSXSEgllNzMw6N+mC+r1AQlEBO3meEAkR/UlfAgnMzJUB3goRBWgip1EAMG99wh36MDqzo86SfIX5Y+VEaw=="], + "@radix-ui/colors": ["@radix-ui/colors@1.0.1", "", {}, "sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg=="], - "@smithy/smithy-client": ["@smithy/smithy-client@4.4.10", "", { "dependencies": { "@smithy/core": "^3.8.0", "@smithy/middleware-endpoint": "^4.1.18", "@smithy/middleware-stack": "^4.0.5", "@smithy/protocol-http": "^5.1.3", "@smithy/types": "^4.3.2", "@smithy/util-stream": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-iW6HjXqN0oPtRS0NK/zzZ4zZeGESIFcxj2FkWed3mcK8jdSdHzvnCKXSjvewESKAgGKAbJRA+OsaqKhkdYRbQQ=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="], - "@smithy/types": ["@smithy/types@4.3.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA=="], + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA=="], - "@smithy/url-parser": ["@smithy/url-parser@4.0.5", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.5", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-j+733Um7f1/DXjYhCbvNXABV53NyCRRA54C7bNEIxNPs0YjfRxeMKjjgm2jvTYrciZyCjsicHwQ6Q0ylo+NAUw=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-id": "1.0.1", "@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-controllable-state": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg=="], - "@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA=="], - "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="], + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="], - "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg=="], + "@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="], - "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="], + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA=="], - "@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-escape-keydown": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg=="], - "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.0.26", "", { "dependencies": { "@smithy/property-provider": "^4.0.5", "@smithy/smithy-client": "^4.4.10", "@smithy/types": "^4.3.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-xgl75aHIS/3rrGp7iTxQAOELYeyiwBu+eEgAk4xfKwJJ0L8VUjhO2shsDpeil54BOFsqmk5xfdesiewbUY5tKQ=="], + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA=="], - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.0.26", "", { "dependencies": { "@smithy/config-resolver": "^4.1.5", "@smithy/credential-provider-imds": "^4.0.7", "@smithy/node-config-provider": "^4.1.4", "@smithy/property-provider": "^4.0.5", "@smithy/smithy-client": "^4.4.10", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-z81yyIkGiLLYVDetKTUeCZQ8x20EEzvQjrqJtb/mXnevLq2+w3XCEWTJ2pMp401b6BkEkHVfXb/cROBpVauLMQ=="], + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ=="], - "@smithy/util-endpoints": ["@smithy/util-endpoints@3.0.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.1.4", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-klGBP+RpBp6V5JbrY2C/VKnHXn3d5V2YrifZbmMY8os7M6m8wdYFoO6w/fe5VkP+YVwrEktW3IWYaSQVNZJ8oQ=="], + "@radix-ui/react-id": ["@radix-ui/react-id@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ=="], - "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.0.6", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-dismissable-layer": "1.0.4", "@radix-ui/react-focus-guards": "1.0.1", "@radix-ui/react-focus-scope": "1.0.3", "@radix-ui/react-id": "1.0.1", "@radix-ui/react-popper": "1.1.2", "@radix-ui/react-portal": "1.0.3", "@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-slot": "1.0.2", "@radix-ui/react-use-controllable-state": "1.0.1", "aria-hidden": "^1.1.1", "react-remove-scroll": "2.5.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-cZ4defGpkZ0qTRtlIBzJLSzL6ht7ofhhW4i1+pkemjV1IKXm0wgCRnee154qlV6r9Ttunmh2TNZhMfV2bavUyA=="], - "@smithy/util-middleware": ["@smithy/util-middleware@4.0.5", "", { "dependencies": { "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-N40PfqsZHRSsByGB81HhSo+uvMxEHT+9e255S53pfBw/wI6WKDI7Jw9oyu5tJTLwZzV5DsMha3ji8jk9dsHmQQ=="], + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.1.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.0.3", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1", "@radix-ui/react-use-rect": "1.0.1", "@radix-ui/react-use-size": "1.0.1", "@radix-ui/rect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg=="], - "@smithy/util-retry": ["@smithy/util-retry@4.0.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.0.7", "@smithy/types": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-TTO6rt0ppK70alZpkjwy+3nQlTiqNfoXja+qwuAchIEAIoSZW8Qyd76dvBv3I5bCpE38APafG23Y/u270NspiQ=="], + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA=="], - "@smithy/util-stream": ["@smithy/util-stream@4.2.4", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.1.1", "@smithy/node-http-handler": "^4.1.1", "@smithy/types": "^4.3.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-vSKnvNZX2BXzl0U2RgCLOwWaAP9x/ddd/XobPK02pCbzRm5s55M53uwb1rl/Ts7RXZvdJZerPkA+en2FDghLuQ=="], + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg=="], - "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg=="], + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="], - "@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-collection": "1.0.3", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-direction": "1.0.1", "@radix-ui/react-id": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-controllable-state": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ=="], - "@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="], - "@solid-primitives/keyed": ["@solid-primitives/keyed@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-BgoEdqPw48URnI+L5sZIHdF4ua4Las1eWEBBPaoSFs42kkhnHue+rwCBPL2Z9ebOyQ75sUhUfOETdJfmv0D6Kg=="], + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-controllable-state": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg=="], - "@solid-primitives/map": ["@solid-primitives/map@0.4.13", "", { "dependencies": { "@solid-primitives/trigger": "^1.1.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew=="], + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-direction": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-roving-focus": "1.0.4", "@radix-ui/react-toggle": "1.0.3", "@radix-ui/react-use-controllable-state": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A=="], - "@solid-primitives/media": ["@solid-primitives/media@2.3.3", "", { "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" } }, "sha512-hQ4hLOGvfbugQi5Eu1BFWAIJGIAzztq9x0h02xgBGl2l0Jaa3h7tg6bz5tV1NSuNYVGio4rPoa7zVQQLkkx9dA=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.0.6", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-dismissable-layer": "1.0.4", "@radix-ui/react-id": "1.0.1", "@radix-ui/react-popper": "1.1.2", "@radix-ui/react-portal": "1.0.3", "@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-slot": "1.0.2", "@radix-ui/react-use-controllable-state": "1.0.1", "@radix-ui/react-visually-hidden": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg=="], - "@solid-primitives/props": ["@solid-primitives/props@3.2.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-lZOTwFJajBrshSyg14nBMEP0h8MXzPowGO0s3OeiR3z6nXHTfj0FhzDtJMv+VYoRJKQHG2QRnJTgCzK6erARAw=="], + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="], - "@solid-primitives/refs": ["@solid-primitives/refs@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-K7tf2thy7L+YJjdqXspXOg5xvNEOH8tgEWsp0+1mQk3obHBRD6hEjYZk7p7FlJphSZImS35je3UfmWuD7MhDfg=="], + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA=="], - "@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "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" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="], + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg=="], - "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="], - "@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="], + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/rect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw=="], - "@solid-primitives/storage": ["@solid-primitives/storage@4.3.1", "", { "dependencies": { "@solid-primitives/utils": "^6.3.0" }, "peerDependencies": { "@tauri-apps/plugin-store": "*", "solid-js": "^1.6.12" }, "optionalPeers": ["@tauri-apps/plugin-store"] }, "sha512-xAJsY2pvXrAaCai4N2grmWY3xh5om9suTDVzGkRF5JBpDzs3Apk+xIovdTErbW0iCzXIEefENXb9xmSzdjuLYA=="], + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react"] }, "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g=="], - "@solid-primitives/trigger": ["@solid-primitives/trigger@1.2.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-IWoptVc0SWYgmpBPpCMehS5b07+tpFcvw15tOQ3QbXedSYn6KP8zCjPkHNzMxcOvOicTneleeZDP7lqmz+PQ6g=="], + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA=="], - "@solid-primitives/utils": ["@solid-primitives/utils@6.3.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ=="], + "@radix-ui/rect": ["@radix-ui/rect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ=="], - "@solidjs/meta": ["@solidjs/meta@0.29.4", "", { "peerDependencies": { "solid-js": ">=1.8.4" } }, "sha512-zdIWBGpR9zGx1p1bzIPqF5Gs+Ks/BH8R6fWhmUa/dcK1L2rUC8BAcZJzNRYBQv74kScf1TSOs0EY//Vd/I0V8g=="], + "@remix-run/node-fetch-server": ["@remix-run/node-fetch-server@0.8.1", "", {}, "sha512-J1dev372wtJqmqn9U/qbpbZxbJSQrogNN2+Qv1lKlpATpe/WQ9aCZfl/xSb9d2Rgh1IyLSvNxZAXPZxruO6Xig=="], - "@solidjs/router": ["@solidjs/router@0.15.3", "", { "peerDependencies": { "solid-js": "^1.8.6" } }, "sha512-iEbW8UKok2Oio7o6Y4VTzLj+KFCmQPGEpm1fS3xixwFBdclFVBvaQVeibl1jys4cujfAK5Kn6+uG2uBm3lxOMw=="], + "@remix-run/router": ["@remix-run/router@1.9.0", "", {}, "sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA=="], - "@solidjs/start": ["@solidjs/start@1.1.7", "", { "dependencies": { "@tanstack/server-functions-plugin": "1.121.21", "@vinxi/plugin-directives": "^0.5.0", "@vinxi/server-components": "^0.5.0", "defu": "^6.1.2", "error-stack-parser": "^2.1.4", "html-to-image": "^1.11.11", "radix3": "^1.1.0", "seroval": "^1.0.2", "seroval-plugins": "^1.0.2", "shiki": "^1.26.1", "source-map-js": "^1.0.2", "terracotta": "^1.0.4", "tinyglobby": "^0.2.2", "vite-plugin-solid": "^2.11.1" }, "peerDependencies": { "vinxi": "^0.5.7" } }, "sha512-30nUFzCpCVH7ORtHlO4ZE+VLG3g3EP+x+ceLLJBFRXIVuFQ1p203xZvVCXWqUPydtK78O5w3nIkWA/tLtF0Ybg=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - "@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="], + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], - "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="], - "@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="], - "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="], - "@tanstack/directive-functions-plugin": ["@tanstack/directive-functions-plugin@1.121.21", "", { "dependencies": { "@babel/code-frame": "7.26.2", "@babel/core": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-utils": "^1.121.21", "babel-dead-code-elimination": "^1.0.10", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "vite": ">=6.0.0" } }, "sha512-B9z/HbF7gJBaRHieyX7f2uQ4LpLLAVAEutBZipH6w+CYD6RHRJvSVPzECGHF7icFhNWTiJQL2QR6K07s59yzEw=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="], - "@tanstack/router-utils": ["@tanstack/router-utils@1.131.2", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/parser": "^7.27.5", "@babel/preset-typescript": "^7.27.1", "ansis": "^4.1.0", "diff": "^8.0.2" } }, "sha512-sr3x0d2sx9YIJoVth0QnfEcAcl+39sQYaNQxThtHmRpyeFYNyM2TTH+Ud3TNEnI3bbzmLYEUD+7YqB987GzhDA=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="], - "@tanstack/server-functions-plugin": ["@tanstack/server-functions-plugin@1.121.21", "", { "dependencies": { "@babel/code-frame": "7.26.2", "@babel/core": "^7.26.8", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9", "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/directive-functions-plugin": "1.121.21", "babel-dead-code-elimination": "^1.0.9", "tiny-invariant": "^1.3.3" } }, "sha512-a05fzK+jBGacsSAc1vE8an7lpBh4H0PyIEcivtEyHLomgSeElAJxm9E2It/0nYRZ5Lh23m0okbhzJNaYWZpAOg=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="], - "@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="], - "@tsconfig/node22": ["@tsconfig/node22@22.0.2", "", {}, "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="], - "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="], - "@tufjs/models": ["@tufjs/models@2.0.1", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.4" } }, "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="], - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="], - "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="], - "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="], - "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="], - "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="], - "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="], - "@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="], - "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="], - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="], - "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="], - "@types/fontkit": ["@types/fontkit@2.0.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="], - "@types/google-protobuf": ["@types/google-protobuf@3.15.12", "", {}, "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="], - "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + "@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], - "@types/http-cache-semantics": ["@types/http-cache-semantics@4.0.4", "", {}, "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="], + "@shikijs/core": ["@shikijs/core@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3q/mzmw09B2B6PgFNeiaN8pkNOixWS726IHmJEpjDAcneDPMQmUg2cweT9cWXY4XcyQS3i6mOOUgQz9RRUP6HA=="], - "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg=="], - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ=="], - "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="], + "@shikijs/langs": ["@shikijs/langs@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA=="], - "@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="], + "@shikijs/themes": ["@shikijs/themes@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ=="], - "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + "@shikijs/transformers": ["@shikijs/transformers@3.9.2", "", { "dependencies": { "@shikijs/core": "3.9.2", "@shikijs/types": "3.9.2" } }, "sha512-MW5hT4TyUp6bNAgTExRYLk1NNasVQMTCw1kgbxHcEC0O5cbepPWaB+1k+JzW9r3SP2/R8kiens8/3E6hGKfgsA=="], - "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="], + "@shikijs/types": ["@shikijs/types@3.9.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw=="], - "@types/micromatch": ["@types/micromatch@4.0.9", "", { "dependencies": { "@types/braces": "*" } }, "sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg=="], + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + "@sindresorhus/is": ["@sindresorhus/is@7.1.1", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="], - "@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="], + "@slack/bolt": ["@slack/bolt@3.22.0", "", { "dependencies": { "@slack/logger": "^4.0.0", "@slack/oauth": "^2.6.3", "@slack/socket-mode": "^1.3.6", "@slack/types": "^2.13.0", "@slack/web-api": "^6.13.0", "@types/express": "^4.16.1", "@types/promise.allsettled": "^1.0.3", "@types/tsscmp": "^1.0.0", "axios": "^1.7.4", "express": "^4.21.0", "path-to-regexp": "^8.1.0", "promise.allsettled": "^1.0.2", "raw-body": "^2.3.3", "tsscmp": "^1.0.6" } }, "sha512-iKDqGPEJDnrVwxSVlFW6OKTkijd7s4qLBeSufoBsTM0reTyfdp/5izIQVkxNfzjHi3o6qjdYbRXkYad5HBsBog=="], - "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@slack/logger": ["@slack/logger@4.0.0", "", { "dependencies": { "@types/node": ">=18.0.0" } }, "sha512-Wz7QYfPAlG/DR+DfABddUZeNgoeY7d1J39OCR2jR+v7VBsB8ezulDK5szTnDDPDwLH5IWhLvXIHlCFZV7MSKgA=="], - "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], + "@slack/oauth": ["@slack/oauth@2.6.3", "", { "dependencies": { "@slack/logger": "^3.0.0", "@slack/web-api": "^6.12.1", "@types/jsonwebtoken": "^8.3.7", "@types/node": ">=12", "jsonwebtoken": "^9.0.0", "lodash.isstring": "^4.0.1" } }, "sha512-1amXs6xRkJpoH6zSgjVPgGEJXCibKNff9WNDijcejIuVy1HFAl1adh7lehaGNiHhTWfQkfKxBiF+BGn56kvoFw=="], - "@types/pg": ["@types/pg@8.15.4", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg=="], + "@slack/socket-mode": ["@slack/socket-mode@1.3.6", "", { "dependencies": { "@slack/logger": "^3.0.0", "@slack/web-api": "^6.12.1", "@types/node": ">=12.0.0", "@types/ws": "^7.4.7", "eventemitter3": "^5", "finity": "^0.5.4", "ws": "^7.5.3" } }, "sha512-G+im7OP7jVqHhiNSdHgv2VVrnN5U7KY845/5EZimZkrD4ZmtV0P3BiWkgeJhPtdLuM7C7i6+M6h6Bh+S4OOalA=="], - "@types/react": ["@types/react@19.1.9", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA=="], + "@slack/types": ["@slack/types@2.19.0", "", {}, "sha512-7+QZ38HGcNh/b/7MpvPG6jnw7mliV6UmrquJLqgdxkzJgQEYUcEztvFWRU49z0x4vthF0ixL5lTK601AXrS8IA=="], - "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], + "@slack/web-api": ["@slack/web-api@6.13.0", "", { "dependencies": { "@slack/logger": "^3.0.0", "@slack/types": "^2.11.0", "@types/is-stream": "^1.1.0", "@types/node": ">=12.0.0", "axios": "^1.7.4", "eventemitter3": "^3.1.0", "form-data": "^2.5.0", "is-electron": "2.2.2", "is-stream": "^1.1.0", "p-queue": "^6.6.1", "p-retry": "^4.0.0" } }, "sha512-dv65crIgdh9ZYHrevLU6XFHTQwTyDmNqEqzuIrV+Vqe/vgiG6w37oex5ePDU1RGm2IJ90H8iOvHFvzdEO/vB+g=="], - "@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="], + "@smithy/abort-controller": ["@smithy/abort-controller@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA=="], - "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="], + "@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA=="], - "@types/semver": ["@types/semver@7.7.0", "", {}, "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA=="], + "@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.1", "", { "dependencies": { "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ=="], - "@types/shimmer": ["@types/shimmer@1.2.0", "", {}, "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg=="], + "@smithy/config-resolver": ["@smithy/config-resolver@4.4.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw=="], - "@types/tmp": ["@types/tmp@0.2.6", "", {}, "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA=="], + "@smithy/core": ["@smithy/core@3.18.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.6", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw=="], - "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ=="], - "@types/turndown": ["@types/turndown@5.0.5", "", {}, "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w=="], + "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="], - "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + "@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.5", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw=="], - "@types/uuid": ["@types/uuid@9.0.8", "", {}, "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA=="], + "@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ=="], - "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.5", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg=="], - "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + "@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.5", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q=="], - "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.39.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.39.1", "@typescript-eslint/types": "^8.39.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw=="], + "@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.6", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.0", "@smithy/chunked-blob-reader-native": "^4.2.1", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.39.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA=="], + "@smithy/hash-node": ["@smithy/hash-node@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.39.1", "", {}, "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw=="], + "@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.39.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.39.1", "@typescript-eslint/tsconfig-utils": "8.39.1", "@typescript-eslint/types": "8.39.1", "@typescript-eslint/visitor-keys": "8.39.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw=="], + "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.39.1", "", { "dependencies": { "@typescript-eslint/types": "8.39.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A=="], + "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="], - "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@smithy/md5-js": ["@smithy/md5-js@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg=="], - "@vercel/nft": ["@vercel/nft@0.29.4", "", { "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0", "@rollup/pluginutils": "^5.1.3", "acorn": "^8.6.0", "acorn-import-attributes": "^1.9.5", "async-sema": "^3.1.1", "bindings": "^1.4.0", "estree-walker": "2.0.2", "glob": "^10.4.5", "graceful-fs": "^4.2.9", "node-gyp-build": "^4.2.2", "picomatch": "^4.0.2", "resolve-from": "^5.0.0" }, "bin": { "nft": "out/cli.js" } }, "sha512-6lLqMNX3TuycBPABycx7A9F1bHQR7kiQln6abjFbPrf5C/05qHM9M5E4PeTE59c7z8g6vHnx1Ioihb2AQl7BTA=="], + "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A=="], - "@vinxi/listhen": ["@vinxi/listhen@1.5.6", "", { "dependencies": { "@parcel/watcher": "^2.3.0", "@parcel/watcher-wasm": "2.3.0", "citty": "^0.1.5", "clipboardy": "^4.0.0", "consola": "^3.2.3", "defu": "^6.1.4", "get-port-please": "^3.1.2", "h3": "^1.10.0", "http-shutdown": "^1.2.2", "jiti": "^1.21.0", "mlly": "^1.5.0", "node-forge": "^1.3.1", "pathe": "^1.1.2", "std-env": "^3.7.0", "ufo": "^1.3.2", "untun": "^0.1.3", "uqr": "^0.1.2" }, "bin": { "listen": "bin/listhen.mjs", "listhen": "bin/listhen.mjs" } }, "sha512-WSN1z931BtasZJlgPp704zJFnQFRg7yzSjkm3MzAWQYe4uXFXlFr1hc5Ac2zae5/HDOz5x1/zDM5Cb54vTCnWw=="], + "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.12", "", { "dependencies": { "@smithy/core": "^3.18.5", "@smithy/middleware-serde": "^4.2.6", "@smithy/node-config-provider": "^4.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-middleware": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-9pAX/H+VQPzNbouhDhkW723igBMLgrI8OtX+++M7iKJgg/zY/Ig3i1e6seCcx22FWhE6Q/S61BRdi2wXBORT+A=="], - "@vinxi/plugin-directives": ["@vinxi/plugin-directives@0.5.1", "", { "dependencies": { "@babel/parser": "^7.23.5", "acorn": "^8.10.0", "acorn-jsx": "^5.3.2", "acorn-loose": "^8.3.0", "acorn-typescript": "^1.4.3", "astring": "^1.8.6", "magicast": "^0.2.10", "recast": "^0.23.4", "tslib": "^2.6.2" }, "peerDependencies": { "vinxi": "^0.5.5" } }, "sha512-pH/KIVBvBt7z7cXrUH/9uaqcdxjegFC7+zvkZkdOyWzs+kQD5KPf3cl8kC+5ayzXHT+OMlhGhyitytqN3cGmHg=="], + "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/service-error-classification": "^4.2.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-S4kWNKFowYd0lID7/DBqWHOQxmxlsf0jBaos9chQZUWTVOjSW1Ogyh8/ib5tM+agFDJ/TCxuCTvrnlc+9cIBcQ=="], - "@vinxi/server-components": ["@vinxi/server-components@0.5.1", "", { "dependencies": { "@vinxi/plugin-directives": "0.5.1", "acorn": "^8.10.0", "acorn-loose": "^8.3.0", "acorn-typescript": "^1.4.3", "astring": "^1.8.6", "magicast": "^0.2.10", "recast": "^0.23.4" }, "peerDependencies": { "vinxi": "^0.5.5" } }, "sha512-0BsG95qac3dkhfdRZxqzqYWJE4NvPL7ILlV43B6K6ho1etXWB2e5b0IxsUAUbyqpqiXM7mSRivojuXjb2G4OsQ=="], + "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ=="], - "@vue/compiler-core": ["@vue/compiler-core@3.5.18", "", { "dependencies": { "@babel/parser": "^7.28.0", "@vue/shared": "3.5.18", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw=="], + "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ=="], - "@vue/compiler-dom": ["@vue/compiler-dom@3.5.18", "", { "dependencies": { "@vue/compiler-core": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A=="], + "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg=="], - "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.18", "", { "dependencies": { "@babel/parser": "^7.28.0", "@vue/compiler-core": "3.5.18", "@vue/compiler-dom": "3.5.18", "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18", "estree-walker": "^2.0.2", "magic-string": "^0.30.17", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw=="], - "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g=="], + "@smithy/property-provider": ["@smithy/property-provider@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg=="], - "@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="], + "@smithy/protocol-http": ["@smithy/protocol-http@5.3.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ=="], - "@whatwg-node/disposablestack": ["@whatwg-node/disposablestack@0.0.6", "", { "dependencies": { "@whatwg-node/promise-helpers": "^1.0.0", "tslib": "^2.6.3" } }, "sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw=="], + "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg=="], - "@whatwg-node/fetch": ["@whatwg-node/fetch@0.10.10", "", { "dependencies": { "@whatwg-node/node-fetch": "^0.7.25", "urlpattern-polyfill": "^10.0.0" } }, "sha512-watz4i/Vv4HpoJ+GranJ7HH75Pf+OkPQ63NoVmru6Srgc8VezTArB00i/oQlnn0KWh14gM42F22Qcc9SU9mo/w=="], + "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ=="], - "@whatwg-node/node-fetch": ["@whatwg-node/node-fetch@0.7.25", "", { "dependencies": { "@fastify/busboy": "^3.1.1", "@whatwg-node/disposablestack": "^0.0.6", "@whatwg-node/promise-helpers": "^1.3.2", "tslib": "^2.6.3" } }, "sha512-szCTESNJV+Xd56zU6ShOi/JWROxE9IwCic8o5D9z5QECZloas6Ez5tUuKqXTAdu6fHFx1t6C+5gwj8smzOLjtg=="], + "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0" } }, "sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ=="], - "@whatwg-node/promise-helpers": ["@whatwg-node/promise-helpers@1.3.2", "", { "dependencies": { "tslib": "^2.6.3" } }, "sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA=="], + "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA=="], - "@whatwg-node/server": ["@whatwg-node/server@0.9.71", "", { "dependencies": { "@whatwg-node/disposablestack": "^0.0.6", "@whatwg-node/fetch": "^0.10.5", "@whatwg-node/promise-helpers": "^1.2.2", "tslib": "^2.6.3" } }, "sha512-ueFCcIPaMgtuYDS9u0qlUoEvj6GiSsKrwnOLPp9SshqjtcRaR1IEHRjoReq3sXNydsF5i0ZnmuYgXq9dV53t0g=="], + "@smithy/signature-v4": ["@smithy/signature-v4@5.3.5", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w=="], + + "@smithy/smithy-client": ["@smithy/smithy-client@4.9.8", "", { "dependencies": { "@smithy/core": "^3.18.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-stack": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-8xgq3LgKDEFoIrLWBho/oYKyWByw9/corz7vuh1upv7ZBm0ZMjGYBhbn6v643WoIqA9UTcx5A5htEp/YatUwMA=="], + + "@smithy/types": ["@smithy/types@4.9.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA=="], + + "@smithy/url-parser": ["@smithy/url-parser@4.2.5", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ=="], + + "@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="], + + "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="], + + "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="], + + "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="], + + "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="], + + "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.11", "", { "dependencies": { "@smithy/property-provider": "^4.2.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-yHv+r6wSQXEXTPVCIQTNmXVWs7ekBTpMVErjqZoWkYN75HIFN5y9+/+sYOejfAuvxWGvgzgxbTHa/oz61YTbKw=="], + + "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.14", "", { "dependencies": { "@smithy/config-resolver": "^4.4.3", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ljZN3iRvaJUgulfvobIuG97q1iUuCMrvXAlkZ4msY+ZuVHQHDIqn7FKZCEj+bx8omz6kF5yQXms/xhzjIO5XiA=="], + + "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A=="], + + "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="], + + "@smithy/util-middleware": ["@smithy/util-middleware@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA=="], + + "@smithy/util-retry": ["@smithy/util-retry@4.2.5", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg=="], + + "@smithy/util-stream": ["@smithy/util-stream@4.5.6", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ=="], + + "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="], + + "@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="], + + "@smithy/util-waiter": ["@smithy/util-waiter@4.2.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="], + + "@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="], + + "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="], + + "@solid-primitives/active-element": ["@solid-primitives/active-element@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9t5K4aR2naVDj950XU8OjnLgOg94a8k5wr6JNOPK+N5ESLsJDq42c1ZP8UKpewi1R+wplMMxiM6OPKRzbxJY7A=="], + + "@solid-primitives/audio": ["@solid-primitives/audio@1.4.2", "", { "dependencies": { "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-UMD3ORQfI5Ky8yuKPxidDiEazsjv/dsoiKK5yZxLnsgaeNR1Aym3/77h/qT1jBYeXUgj4DX6t7NMpFUSVr14OQ=="], + + "@solid-primitives/bounds": ["@solid-primitives/bounds@0.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/resize-observer": "^2.1.3", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-UbiyKMdSPmtijcEDnYLQL3zzaejpwWDAJJ4Gt5P0hgVs6A72piov0GyNw7V2SroH7NZFwxlYS22YmOr8A5xc1Q=="], + + "@solid-primitives/event-bus": ["@solid-primitives/event-bus@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-l+n10/51neGcMaP3ypYt21bXfoeWh8IaC8k7fYuY3ww2a8S1Zv2N2a7FF5Qn+waTu86l0V8/nRHjkyqVIZBYwA=="], + + "@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="], + + "@solid-primitives/i18n": ["@solid-primitives/i18n@2.2.1", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-TnTnE2Ku11MGYZ1JzhJ8pYscwg1fr9MteoYxPwsfxWfh9Jp5K7RRJncJn9BhOHvNLwROjqOHZ46PT7sPHqbcXw=="], + + "@solid-primitives/keyed": ["@solid-primitives/keyed@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-BgoEdqPw48URnI+L5sZIHdF4ua4Las1eWEBBPaoSFs42kkhnHue+rwCBPL2Z9ebOyQ75sUhUfOETdJfmv0D6Kg=="], + + "@solid-primitives/map": ["@solid-primitives/map@0.4.13", "", { "dependencies": { "@solid-primitives/trigger": "^1.1.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew=="], + + "@solid-primitives/media": ["@solid-primitives/media@2.3.3", "", { "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" } }, "sha512-hQ4hLOGvfbugQi5Eu1BFWAIJGIAzztq9x0h02xgBGl2l0Jaa3h7tg6bz5tV1NSuNYVGio4rPoa7zVQQLkkx9dA=="], + + "@solid-primitives/props": ["@solid-primitives/props@3.2.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-lZOTwFJajBrshSyg14nBMEP0h8MXzPowGO0s3OeiR3z6nXHTfj0FhzDtJMv+VYoRJKQHG2QRnJTgCzK6erARAw=="], + + "@solid-primitives/refs": ["@solid-primitives/refs@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-K7tf2thy7L+YJjdqXspXOg5xvNEOH8tgEWsp0+1mQk3obHBRD6hEjYZk7p7FlJphSZImS35je3UfmWuD7MhDfg=="], + + "@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "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" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="], + + "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="], + + "@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="], + + "@solid-primitives/scroll": ["@solid-primitives/scroll@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-Ejq/Z7zKo/6eIEFr1bFLzXFxiGBCMLuqCM8QB8urr3YdPzjSETFLzYRWUyRiDWaBQN0F7k0SY6S7ig5nWOP7vg=="], + + "@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="], + + "@solid-primitives/storage": ["@solid-primitives/storage@4.3.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "@tauri-apps/plugin-store": "*", "solid-js": "^1.6.12" }, "optionalPeers": ["@tauri-apps/plugin-store"] }, "sha512-ACbNwMZ1s8VAvld6EUXkDkX/US3IhtlPLxg6+B2s9MwNUugwdd51I98LPEaHrdLpqPmyzqgoJe0TxEFlf3Dqrw=="], + + "@solid-primitives/trigger": ["@solid-primitives/trigger@1.2.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-IWoptVc0SWYgmpBPpCMehS5b07+tpFcvw15tOQ3QbXedSYn6KP8zCjPkHNzMxcOvOicTneleeZDP7lqmz+PQ6g=="], + + "@solid-primitives/utils": ["@solid-primitives/utils@6.3.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ=="], + + "@solid-primitives/websocket": ["@solid-primitives/websocket@1.3.1", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-F06tA2FKa5VsnS4E4WEc3jHpsJfXRlMTGOtolugTzCqV3JmJTyvk9UVg1oz6PgGHKGi1CQ91OP8iW34myyJgaQ=="], + + "@solidjs/meta": ["@solidjs/meta@0.29.4", "", { "peerDependencies": { "solid-js": ">=1.8.4" } }, "sha512-zdIWBGpR9zGx1p1bzIPqF5Gs+Ks/BH8R6fWhmUa/dcK1L2rUC8BAcZJzNRYBQv74kScf1TSOs0EY//Vd/I0V8g=="], + + "@solidjs/router": ["@solidjs/router@0.15.4", "", { "peerDependencies": { "solid-js": "^1.8.6" } }, "sha512-WOpgg9a9T638cR+5FGbFi/IV4l2FpmBs1GpIMSPa0Ce9vyJN7Wts+X2PqMf9IYn0zUj2MlSJtm1gp7/HI/n5TQ=="], + + "@solidjs/start": ["@solidjs/start@https://pkg.pr.new/@solidjs/start@dfb2020", { "dependencies": { "@babel/core": "^7.28.3", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.5", "@solidjs/meta": "^0.29.4", "@tanstack/server-functions-plugin": "1.134.5", "@types/babel__traverse": "^7.28.0", "@types/micromatch": "^4.0.9", "cookie-es": "^2.0.0", "defu": "^6.1.4", "error-stack-parser": "^2.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.3", "fast-glob": "^3.3.3", "h3": "npm:h3@2.0.1-rc.4", "html-to-image": "^1.11.13", "micromatch": "^4.0.8", "path-to-regexp": "^8.2.0", "pathe": "^2.0.3", "radix3": "^1.1.2", "seroval": "^1.3.2", "seroval-plugins": "^1.2.1", "shiki": "^1.26.1", "solid-js": "^1.9.9", "source-map-js": "^1.2.1", "srvx": "^0.9.1", "terracotta": "^1.0.6", "vite": "7.1.10", "vite-plugin-solid": "^2.11.9", "vitest": "^4.0.10" } }], + + "@speed-highlight/core": ["@speed-highlight/core@1.2.12", "", {}, "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA=="], + + "@standard-community/standard-json": ["@standard-community/standard-json@0.3.5", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "sury": "^10.0.0", "typebox": "^1.0.17", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-to-json-schema"] }, "sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA=="], + + "@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.9", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + + "@stripe/stripe-js": ["@stripe/stripe-js@8.6.1", "", {}, "sha512-UJ05U2062XDgydbUcETH1AoRQLNhigQ2KmDn1BG8sC3xfzu6JKg95Qt6YozdzFpxl1Npii/02m2LEWFt1RYjVA=="], + + "@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.1.11", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.11" } }, "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.11", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.11", "@tailwindcss/oxide-darwin-arm64": "4.1.11", "@tailwindcss/oxide-darwin-x64": "4.1.11", "@tailwindcss/oxide-freebsd-x64": "4.1.11", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", "@tailwindcss/oxide-linux-x64-musl": "4.1.11", "@tailwindcss/oxide-wasm32-wasi": "4.1.11", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" } }, "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.11", "", { "os": "android", "cpu": "arm64" }, "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11", "", { "os": "linux", "cpu": "arm" }, "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.11", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.11", "", { "os": "win32", "cpu": "x64" }, "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg=="], + + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.11", "", { "dependencies": { "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "tailwindcss": "4.1.11" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw=="], + + "@tanstack/directive-functions-plugin": ["@tanstack/directive-functions-plugin@1.134.5", "", { "dependencies": { "@babel/code-frame": "7.27.1", "@babel/core": "^7.27.7", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", "@tanstack/router-utils": "1.133.19", "babel-dead-code-elimination": "^1.0.10", "pathe": "^2.0.3", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "vite": ">=6.0.0 || >=7.0.0" } }, "sha512-J3oawV8uBRBbPoLgMdyHt+LxzTNuWRKNJJuCLWsm/yq6v0IQSvIVCgfD2+liIiSnDPxGZ8ExduPXy8IzS70eXw=="], + + "@tanstack/router-utils": ["@tanstack/router-utils@1.133.19", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/parser": "^7.27.5", "@babel/preset-typescript": "^7.27.1", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-WEp5D2gPxvlLDRXwD/fV7RXjYtqaqJNXKB/L6OyZEbT+9BG/Ib2d7oG9GSUZNNMGPGYAlhBUOi3xutySsk6rxA=="], + + "@tanstack/server-functions-plugin": ["@tanstack/server-functions-plugin@1.134.5", "", { "dependencies": { "@babel/code-frame": "7.27.1", "@babel/core": "^7.27.7", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", "@tanstack/directive-functions-plugin": "1.134.5", "babel-dead-code-elimination": "^1.0.9", "tiny-invariant": "^1.3.3" } }, "sha512-2sWxq70T+dOEUlE3sHlXjEPhaFZfdPYlWTSkHchWXrFGw2YOAa+hzD6L9wHMjGDQezYd03ue8tQlHG+9Jzbzgw=="], + + "@tauri-apps/api": ["@tauri-apps/api@2.9.0", "", {}, "sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw=="], + + "@tauri-apps/cli": ["@tauri-apps/cli@2.9.4", "", { "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" }, "bin": { "tauri": "tauri.js" } }, "sha512-pvylWC9QckrOS9ATWXIXcgu7g2hKK5xTL5ZQyZU/U0n9l88SEFGcWgLQNa8WZmd+wWIOWhkxOFcOl3i6ubDNNw=="], + + "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9rHkMVtbMhe0AliVbrGpzMahOBg3rwV46JYRELxR9SN6iu1dvPOaMaiC4cP6M/aD1424ziXnnMdYU06RAH8oIw=="], + + "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-VT9ymNuT06f5TLjCZW2hfSxbVtZDhORk7CDUDYiq5TiSYQdxkl8MVBy0CCFFcOk4QAkUmqmVUA9r3YZ/N/vPRQ=="], + + "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.9.4", "", { "os": "linux", "cpu": "arm" }, "sha512-tTWkEPig+2z3Rk0zqZYfjUYcgD+aSm72wdrIhdYobxbQZOBw0zfn50YtWv+av7bm0SHvv75f0l7JuwgZM1HFow=="], + + "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-ql6vJ611qoqRYHxkKPnb2vHa27U+YRKRmIpLMMBeZnfFtZ938eao7402AQCH1mO2+/8ioUhbpy9R/ZcLTXVmkg=="], + + "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-vg7yNn7ICTi6hRrcA/6ff2UpZQP7un3xe3SEld5QM0prgridbKAiXGaCKr3BnUBx/rGXegQlD/wiLcWdiiraSw=="], + + "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.9.4", "", { "os": "linux", "cpu": "none" }, "sha512-l8L+3VxNk6yv5T/Z/gv5ysngmIpsai40B9p6NQQyqYqxImqYX37pqREoEBl1YwG7szGnDibpWhidPrWKR59OJA=="], + + "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-PepPhCXc/xVvE3foykNho46OmCyx47E/aG676vKTVp+mqin5d+IBqDL6wDKiGNT5OTTxKEyNlCQ81Xs2BQhhqA=="], + + "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-zcd1QVffh5tZs1u1SCKUV/V7RRynebgYUNWHuV0FsIF1MjnULUChEXhAhug7usCDq4GZReMJOoXa6rukEozWIw=="], + + "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-/7ZhnP6PY04bEob23q8MH/EoDISdmR1wuNm0k9d5HV7TDMd2GGCDa8dPXA4vJuglJKXIfXqxFmZ4L+J+MO42+w=="], + + "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.9.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-1LmAfaC4Cq+3O1Ir1ksdhczhdtFSTIV51tbAGtbV/mr348O+M52A/xwCCXQank0OcdBxy5BctqkMtuZnQvA8uQ=="], + + "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-EdYd4c9wGvtPB95kqtEyY+bUR+k4kRw3IA30mAQ1jPH6z57AftT8q84qwv0RDp6kkEqOBKxeInKfqi4BESYuqg=="], + + "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.4.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ=="], + + "@tauri-apps/plugin-http": ["@tauri-apps/plugin-http@2.5.4", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-/i4U/9za3mrytTgfRn5RHneKubZE/dwRmshYwyMvNRlkWjvu1m4Ma72kcbVJMZFGXpkbl+qLyWMGrihtWB76Zg=="], + + "@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg=="], + + "@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew=="], + + "@tauri-apps/plugin-os": ["@tauri-apps/plugin-os@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A=="], + + "@tauri-apps/plugin-process": ["@tauri-apps/plugin-process@2.3.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA=="], + + "@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ=="], + + "@tauri-apps/plugin-store": ["@tauri-apps/plugin-store@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA=="], + + "@tauri-apps/plugin-updater": ["@tauri-apps/plugin-updater@2.9.0", "", { "dependencies": { "@tauri-apps/api": "^2.6.0" } }, "sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg=="], + + "@tauri-apps/plugin-window-state": ["@tauri-apps/plugin-window-state@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw=="], + + "@thisbeyond/solid-dnd": ["@thisbeyond/solid-dnd@0.7.5", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@tsconfig/bun": ["@tsconfig/bun@1.0.9", "", {}, "sha512-4M0/Ivfwcpz325z6CwSifOBZYji3DFOEpY6zEUt0+Xi2qRhzwvmqQN9XAHJh3OVvRJuAqVTLU2abdCplvp6mwQ=="], + + "@tsconfig/node22": ["@tsconfig/node22@22.0.2", "", {}, "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], + + "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], + + "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="], + + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], + + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + + "@types/express": ["@types/express@4.17.25", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "^1" } }, "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw=="], + + "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.7", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg=="], + + "@types/fontkit": ["@types/fontkit@2.0.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew=="], + + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + + "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], + + "@types/is-stream": ["@types/is-stream@1.1.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg=="], + + "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/jsonwebtoken": ["@types/jsonwebtoken@8.5.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg=="], + + "@types/katex": ["@types/katex@0.16.7", "", {}, "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="], + + "@types/luxon": ["@types/luxon@3.7.1", "", {}, "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg=="], + + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + + "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="], + + "@types/micromatch": ["@types/micromatch@4.0.10", "", { "dependencies": { "@types/braces": "*" } }, "sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ=="], + + "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + + "@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="], + + "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], + + "@types/promise.allsettled": ["@types/promise.allsettled@1.0.6", "", {}, "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg=="], + + "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + + "@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="], + + "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], + + "@types/react": ["@types/react@18.0.25", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g=="], + + "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], + + "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="], + + "@types/scheduler": ["@types/scheduler@0.26.0", "", {}, "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA=="], + + "@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], + + "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], + + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], + + "@types/tsscmp": ["@types/tsscmp@1.0.2", "", {}, "sha512-cy7BRSU8GYYgxjcx0Py+8lo5MthuDhlyu076KUcYzVNXL23luYgRHkMG2fIFEc6neckeh/ntP82mw+U4QjZq+g=="], + + "@types/tunnel": ["@types/tunnel@0.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA=="], + + "@types/turndown": ["@types/turndown@5.0.5", "", {}, "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w=="], + + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + + "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], + + "@types/ws": ["@types/ws@7.4.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww=="], + + "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20251207.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20251207.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-4QcRnzB0pi9rS0AOvg8kWbmuwHv5X7B2EXHbgcms9+56hsZ8SZrZjNgBJb2rUIodJ4kU5mrkj/xlTTT4r9VcpQ=="], + + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-waWJnuuvkXh4WdpbTjYf7pyahJzx0ycesV2BylyHrE9OxU9FSKcD/cRLQYvbq3YcBSdF7sZwRLDBer7qTeLsYA=="], + + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-3bkD9QuIjxETtp6J1l5X2oKgudJ8z+8fwUq0izCjK1JrIs2vW1aQnbzxhynErSyHWH7URGhHHzcsXHbikckAsg=="], + + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OjrZBq8XJkB7uCQvT1AZ1FPsp+lT0cHxY5SisE+ZTAU6V0IHAZMwJ7J/mnwlGsBcCKRLBT+lX3hgEuOTSwHr9w=="], + + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qhp06OObkwy5B+PlAhAmq+Ls3GVt4LHAovrTRcpLB3Mk3yJ0h9DnIQwPQiayp16TdvTsGHI3jdIX4MGm5L/ghA=="], + + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "x64" }, "sha512-fPRw0zfTBeVmrkgi5Le+sSwoeAz6pIdvcsa1OYZcrspueS9hn3qSC5bLEc5yX4NJP1vItadBqyGLUQ7u8FJjow=="], + + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20251207.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-KxY1i+HxeSFfzZ+HVsKwMGBM79laTRZv1ibFqHu22CEsfSPDt4yiV1QFis8Nw7OBXswNqJG/UGqY47VP8FeTvw=="], + + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20251207.1", "", { "os": "win32", "cpu": "x64" }, "sha512-5l51HlXjX7lXwo65DEl1IaCFLjmkMtL6K3NrSEamPNeNTtTQwZRa3pQ9V65dCglnnCQ0M3+VF1RqzC7FU0iDKg=="], + + "@typescript/vfs": ["@typescript/vfs@1.6.2", "", { "dependencies": { "debug": "^4.1.1" }, "peerDependencies": { "typescript": "*" } }, "sha512-hoBwJwcbKHmvd2QVebiytN1aELvpk9B74B4L1mFm/XT1Q/VOYAWl2vQ9AWRFtQq8zmz6enTpfTV8WRc4ATjW/g=="], + + "@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.2", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg=="], + + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + + "@vercel/oidc": ["@vercel/oidc@3.0.5", "", {}, "sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], + + "@vitest/expect": ["@vitest/expect@4.0.16", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.16", "@vitest/utils": "4.0.16", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA=="], + + "@vitest/mocker": ["@vitest/mocker@4.0.16", "", { "dependencies": { "@vitest/spy": "4.0.16", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@4.0.16", "", { "dependencies": { "tinyrainbow": "^3.0.3" } }, "sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA=="], + + "@vitest/runner": ["@vitest/runner@4.0.16", "", { "dependencies": { "@vitest/utils": "4.0.16", "pathe": "^2.0.3" } }, "sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q=="], + + "@vitest/snapshot": ["@vitest/snapshot@4.0.16", "", { "dependencies": { "@vitest/pretty-format": "4.0.16", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA=="], + + "@vitest/spy": ["@vitest/spy@4.0.16", "", {}, "sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw=="], + + "@vitest/utils": ["@vitest/utils@4.0.16", "", { "dependencies": { "@vitest/pretty-format": "4.0.16", "tinyrainbow": "^3.0.3" } }, "sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA=="], + + "@webgpu/types": ["@webgpu/types@0.1.54", "", {}, "sha512-81oaalC8LFrXjhsczomEQ0u3jG+TqE6V9QHLA8GNZq/Rnot0KDugu3LhSYSlie8tSdooAN1Hov05asrUUp9qgg=="], "@zip.js/zip.js": ["@zip.js/zip.js@2.7.62", "", {}, "sha512-OaLvZ8j4gCkLn048ypkZu29KX30r8/OfFF2w4Jo5WXFr+J04J+lzJ5TKZBVgFXhlvSkqNFQdfnY1Q8TMTCyBVA=="], @@ -1143,37 +1924,37 @@ "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], - "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], - "acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="], - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - "acorn-loose": ["acorn-loose@8.5.2", "", { "dependencies": { "acorn": "^8.15.0" } }, "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A=="], - - "acorn-typescript": ["acorn-typescript@1.4.13", "", { "peerDependencies": { "acorn": ">=8.9.0" } }, "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q=="], - "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + + "ai": ["ai@5.0.119", "", { "dependencies": { "@ai-sdk/gateway": "2.0.25", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-HUOwhc17fl2SZTJGZyA/99aNu706qKfXaUBCy9vgZiXBwrxg2eTzn2BCz7kmYDsfx6Fg2ACBy2icm41bsDXCTw=="], - "ai": ["ai@5.0.8", "", { "dependencies": { "@ai-sdk/gateway": "1.0.4", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.1", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-qbnhj046UvG30V1S5WhjBn+RBGEAmi8PSZWqMhRsE3EPxvO5BcePXTZFA23e9MYyWS9zr4Vm8Mv3wQXwLmtIBw=="], + "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], - "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], - "ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + "any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="], - "ansis": ["ansis@4.1.0", "", {}, "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w=="], + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -1187,13 +1968,23 @@ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], + "array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="], - "ast-module-types": ["ast-module-types@6.0.1", "", {}, "sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA=="], + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], + + "array.prototype.map": ["array.prototype.map@1.0.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-array-method-boxes-properly": "^1.0.0", "es-object-atoms": "^1.0.0", "is-string": "^1.1.1" } }, "sha512-YocPM7bYYu2hXGxWpb5vwZ8cMeudNHYtYBcUDY4Z1GWa53qcnQMWSl25jeBHNzitjl9HW2AWW4ro/S/nftUaOQ=="], - "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], @@ -1203,65 +1994,75 @@ "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], - "async-lock": ["async-lock@1.4.1", "", {}, "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="], + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], - "async-sema": ["async-sema@3.1.1", "", {}, "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg=="], + "autoprefixer": ["autoprefixer@10.4.22", "", { "dependencies": { "browserslist": "^4.27.0", "caniuse-lite": "^1.0.30001754", "fraction.js": "^5.3.4", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg=="], "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + "await-to-js": ["await-to-js@3.0.0", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="], + "aws-sdk": ["aws-sdk@2.1692.0", "", { "dependencies": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", "xml2js": "0.6.2" } }, "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw=="], - "aws4fetch": ["aws4fetch@1.0.18", "", {}, "sha512-3Cf+YaUl07p24MoQ46rFwulAmiyCwH2+1zw1ZyPAX5OtJ34Hh185DwB8y/qRLb6cYYYtSFJ9pthyLc0MD4e8sQ=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + + "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + + "axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], - "b4a": ["b4a@1.6.7", "", {}, "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg=="], + "b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.10", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA=="], - "babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.39.8", "", { "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", "validate-html-nesting": "^1.2.1" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-/MVOIIjonylDXnrWmG23ZX82m9mtKATsVHB7zYlPfDR9Vdd/NBE48if+wv27bSkBtyO7EPMUlcUc4J63QwuACQ=="], + "babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.3", "", { "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" } }, "sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w=="], + + "babel-plugin-module-resolver": ["babel-plugin-module-resolver@5.0.2", "", { "dependencies": { "find-babel-config": "^2.1.1", "glob": "^9.3.3", "pkg-up": "^3.1.0", "reselect": "^4.1.7", "resolve": "^1.22.8" } }, "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg=="], - "babel-preset-solid": ["babel-preset-solid@1.9.6", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.39.8" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-HXTK9f93QxoH8dYn1M2mJdOlWgMsR88Lg/ul6QCZGkNTktjTE5HAf93YxQumHoCudLEtZrU1cFCMFOVho6GqFg=="], + "babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="], "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "bare-events": ["bare-events@2.6.0", "", {}, "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg=="], - - "bare-fs": ["bare-fs@4.1.6", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ=="], - - "bare-os": ["bare-os@3.6.1", "", {}, "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g=="], - - "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], - - "bare-stream": ["bare-stream@2.6.5", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA=="], + "bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="], "base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.30", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-aTUKW4ptQhS64+v2d6IkPzymEzzhw+G0bA1g3uBRV3+ntkH+svttKseW5IOR4Ed6NUVKqnY7qT3dKvzQ7io4AA=="], + "bcp-47": ["bcp-47@2.1.0", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w=="], "bcp-47-match": ["bcp-47-match@2.0.3", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="], - "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], - "bin-links": ["bin-links@4.0.4", "", { "dependencies": { "cmd-shim": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", "read-cmd-shim": "^4.0.0", "write-file-atomic": "^5.0.0" } }, "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA=="], + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], - "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], + "binary": ["binary@0.3.0", "", { "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" } }, "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg=="], - "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], "blob-to-buffer": ["blob-to-buffer@1.2.9", "", {}, "sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA=="], - "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], + "bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="], + + "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], + + "bonjour-service": ["bonjour-service@1.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA=="], "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], - "bowser": ["bowser@2.11.0", "", {}, "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA=="], + "bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="], + + "bowser": ["bowser@2.12.1", "", {}, "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw=="], "boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="], @@ -1271,29 +2072,39 @@ "brotli": ["brotli@1.3.3", "", { "dependencies": { "base64-js": "^1.1.2" } }, "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="], - "browserslist": ["browserslist@4.25.1", "", { "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw=="], + "browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="], "buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="], "buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="], + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "builtin-modules": ["builtin-modules@3.3.0", "", {}, "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw=="], + "buffers": ["buffers@0.1.1", "", {}, "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="], - "bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="], + "bun-ffi-structs": ["bun-ffi-structs@0.1.2", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-Lh1oQAYHDcnesJauieA4UNkWGXY9hYck7OA5IaRwE3Bp6K2F2pJSNYqq+hIy7P3uOvo3km3oxS8304g5gDMl/w=="], - "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + "bun-pty": ["bun-pty@0.4.4", "", {}, "sha512-WK4G6uWsZgu1v4hKIlw6G1q2AOf8Rbga2Yr7RnxArVjjyb+mtVa/CFc9GOJf+OYSJSH8k7LonAtQOVeNAddRyg=="], - "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], - "c12": ["c12@2.0.1", "", { "dependencies": { "chokidar": "^4.0.1", "confbox": "^0.1.7", "defu": "^6.1.4", "dotenv": "^16.4.5", "giget": "^1.2.3", "jiti": "^2.3.0", "mlly": "^1.7.1", "ohash": "^1.1.4", "pathe": "^1.1.2", "perfect-debounce": "^1.0.0", "pkg-types": "^1.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A=="], + "bun-webgpu": ["bun-webgpu@0.1.4", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.4", "bun-webgpu-darwin-x64": "^0.1.4", "bun-webgpu-linux-x64": "^0.1.4", "bun-webgpu-win32-x64": "^0.1.4" } }, "sha512-Kw+HoXl1PMWJTh9wvh63SSRofTA8vYBFCw0XEP1V1fFdQEDhI8Sgf73sdndE/oDpN/7CMx0Yv/q8FCvO39ROMQ=="], - "cacache": ["cacache@18.0.4", "", { "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", "ssri": "^10.0.0", "tar": "^6.1.11", "unique-filename": "^3.0.0" } }, "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ=="], + "bun-webgpu-darwin-arm64": ["bun-webgpu-darwin-arm64@0.1.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eDgLN9teKTfmvrCqgwwmWNsNszxYs7IZdCqk0S1DCarvMhr4wcajoSBlA/nQA0/owwLduPTS8xxCnQp4/N/gDg=="], - "cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="], + "bun-webgpu-darwin-x64": ["bun-webgpu-darwin-x64@0.1.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-X+PjwJUWenUmdQBP8EtdItMyieQ6Nlpn+BH518oaouDiSnWj5+b0Y7DNDZJq7Ezom4EaxmqL/uGYZK3aCQ7CXg=="], - "cacheable-request": ["cacheable-request@7.0.4", "", { "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" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="], + "bun-webgpu-linux-x64": ["bun-webgpu-linux-x64@0.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-zMLs2YIGB+/jxrYFXaFhVKX/GBt05UTF45lc9srcHc9JXGjEj+12CIo1CHLTAWatXMTqt0Jsu6ukWEoWVT/ayA=="], + + "bun-webgpu-win32-x64": ["bun-webgpu-win32-x64@0.1.4", "", { "os": "win32", "cpu": "x64" }, "sha512-Z5yAK28xrcm8Wb5k7TZ8FJKpOI/r+aVCRdlHYAqI2SDJFN3nD4mJs900X6kNVmG/xFzb5yOuKVYWGg+6ZXWbyA=="], + + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="], "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], @@ -1301,15 +2112,21 @@ "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "callsite": ["callsite@1.0.0", "", {}, "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ=="], + "camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="], "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001731", "", {}, "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg=="], + "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001756", "", {}, "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], + "chai": ["chai@6.2.1", "", {}, "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg=="], + + "chainsaw": ["chainsaw@0.1.0", "", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="], + + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], @@ -1319,36 +2136,40 @@ "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + "chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="], + + "cheerio": ["cheerio@1.0.0-rc.12", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "htmlparser2": "^8.0.1", "parse5": "^7.0.0", "parse5-htmlparser2-tree-adapter": "^7.0.0" } }, "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q=="], + + "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - "ci-info": ["ci-info@4.3.0", "", {}, "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ=="], + "ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], - "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], - - "clean-git-ref": ["clean-git-ref@2.0.1", "", {}, "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw=="], + "classnames": ["classnames@2.3.2", "", {}, "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="], - "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], + "cli-spinners": ["cli-spinners@3.3.0", "", {}, "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ=="], + "clipboardy": ["clipboardy@4.0.0", "", { "dependencies": { "execa": "^8.0.1", "is-wsl": "^3.1.0", "is64bit": "^2.0.0" } }, "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w=="], "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], - "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="], + "cloudflare": ["cloudflare@5.2.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-dVzqDpPFYR9ApEC9e+JJshFJZXcw4HzM8W+3DHzO5oy9+8rLC53G7x6fEf9A7/gSuSCxuvndzui5qJKftfIM9A=="], "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], - "cmd-shim": ["cmd-shim@6.0.3", "", {}, "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA=="], - "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], @@ -1361,27 +2182,25 @@ "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], - "colorspace": ["colorspace@1.1.4", "", { "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" } }, "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w=="], + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], - "commander": ["commander@13.0.0", "", {}, "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ=="], + "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], - "common-path-prefix": ["common-path-prefix@3.0.0", "", {}, "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w=="], + "compress-commons": ["compress-commons@6.0.2", "", { "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", "is-stream": "^2.0.1", "normalize-path": "^3.0.0", "readable-stream": "^4.0.0" } }, "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg=="], - "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + "condense-newlines": ["condense-newlines@0.2.1", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-whitespace": "^0.3.0", "kind-of": "^3.0.2" } }, "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg=="], - "compatx": ["compatx@0.2.0", "", {}, "sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA=="], + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "compress-commons": ["compress-commons@6.0.2", "", { "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", "is-stream": "^2.0.1", "normalize-path": "^3.0.0", "readable-stream": "^4.0.0" } }, "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg=="], - - "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="], "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], - "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -1389,11 +2208,9 @@ "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], - "cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="], - - "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], - "copy-file": ["copy-file@11.1.0", "", { "dependencies": { "graceful-fs": "^4.2.11", "p-event": "^6.0.0" } }, "sha512-X8XDzyvYaA6msMyAM575CUoygY5b44QzLcGRKsK3MFmXcOvQa518dNPLsKYwkYsn72g3EiW+LE0ytd/FlqWmyw=="], + "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], @@ -1403,105 +2220,107 @@ "crc32-stream": ["crc32-stream@6.0.0", "", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^4.0.0" } }, "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g=="], - "cron-parser": ["cron-parser@4.9.0", "", { "dependencies": { "luxon": "^3.2.1" } }, "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q=="], - - "croner": ["croner@9.1.0", "", {}, "sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g=="], - "cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], + "crossws": ["crossws@0.4.1", "", { "peerDependencies": { "srvx": ">=0.7.1" }, "optionalPeers": ["srvx"] }, "sha512-E7WKBcHVhAVrY6JYD5kteNqVq1GSZxqGrdSiwXR9at+XHi43HJoCQKXcCczR5LBnBquFZPsB3o7HklulKoBU5w=="], - "css-selector-parser": ["css-selector-parser@3.1.3", "", {}, "sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg=="], + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-selector-parser": ["css-selector-parser@3.2.0", "", {}, "sha512-L1bdkNKUP5WYxiW5dW6vA2hd3sL8BdRNLy2FCX0rLVise4eNw9nBdeBuJHxlELieSE2H1f6bYQFfwVUwWCV9rQ=="], "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="], + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], - "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], - "dax-sh": ["dax-sh@0.43.2", "", { "dependencies": { "@deno/shim-deno": "~0.19.0", "undici-types": "^5.26" } }, "sha512-uULa1sSIHgXKGCqJ/pA0zsnzbHlVnuq7g8O2fkHokWFNwEGIhh5lAJlxZa1POG5En5ba7AU4KcBAvGQWMMf8rg=="], + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], - "db0": ["db0@0.3.2", "", { "peerDependencies": { "@electric-sql/pglite": "*", "@libsql/client": "*", "better-sqlite3": "*", "drizzle-orm": "*", "mysql2": "*", "sqlite3": "*" }, "optionalPeers": ["@electric-sql/pglite", "@libsql/client", "better-sqlite3", "drizzle-orm", "mysql2", "sqlite3"] }, "sha512-xzWNQ6jk/+NtdfLyXEipbX55dmDSeteLFt/ayF+wZUU5bzKgmrDOxmInUTbyVRp46YwnJdkDA1KhB7WIXFofJw=="], + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], - "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], - "decache": ["decache@4.6.2", "", { "dependencies": { "callsite": "^1.0.0" } }, "sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw=="], + "db0": ["db0@0.3.4", "", { "peerDependencies": { "@electric-sql/pglite": "*", "@libsql/client": "*", "better-sqlite3": "*", "drizzle-orm": "*", "mysql2": "*", "sqlite3": "*" }, "optionalPeers": ["@electric-sql/pglite", "@libsql/client", "better-sqlite3", "drizzle-orm", "mysql2", "sqlite3"] }, "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], "decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="], - "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], - - "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], - "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], - "default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="], - - "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], + "default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="], - "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="], + "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], - "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], - "detective-amd": ["detective-amd@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "escodegen": "^2.1.0", "get-amd-module-type": "^6.0.1", "node-source-walk": "^7.0.1" }, "bin": { "detective-amd": "bin/cli.js" } }, "sha512-TtyZ3OhwUoEEIhTFoc1C9IyJIud3y+xYkSRjmvCt65+ycQuc3VcBrPRTMWoO/AnuCyOB8T5gky+xf7Igxtjd3g=="], + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], - "detective-cjs": ["detective-cjs@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" } }, "sha512-tLTQsWvd2WMcmn/60T2inEJNhJoi7a//PQ7DwRKEj1yEeiQs4mrONgsUtEJKnZmrGWBBmE0kJ1vqOG/NAxwaJw=="], + "deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="], - "detective-es6": ["detective-es6@5.0.1", "", { "dependencies": { "node-source-walk": "^7.0.1" } }, "sha512-XusTPuewnSUdoxRSx8OOI6xIA/uld/wMQwYsouvFN2LAg7HgP06NF1lHRV3x6BZxyL2Kkoih4ewcq8hcbGtwew=="], + "devalue": ["devalue@5.5.0", "", {}, "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w=="], - "detective-postcss": ["detective-postcss@7.0.1", "", { "dependencies": { "is-url": "^1.2.4", "postcss-values-parser": "^6.0.2" }, "peerDependencies": { "postcss": "^8.4.47" } }, "sha512-bEOVpHU9picRZux5XnwGsmCN4+8oZo7vSW0O0/Enq/TO5R2pIAP2279NsszpJR7ocnQt4WXU0+nnh/0JuK4KHQ=="], + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], - "detective-sass": ["detective-sass@6.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-jSGPO8QDy7K7pztUmGC6aiHkexBQT4GIH+mBAL9ZyBmnUIOFbkfZnO8wPRRJFP/QP83irObgsZHCoDHZ173tRw=="], + "dfa": ["dfa@1.2.0", "", {}, "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="], - "detective-scss": ["detective-scss@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-MAyPYRgS6DCiS6n6AoSBJXLGVOydsr9huwXORUlJ37K3YLyiN0vYHpzs3AdJOgHobBfispokoqrEon9rbmKacg=="], + "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], - "detective-stylus": ["detective-stylus@5.0.1", "", {}, "sha512-Dgn0bUqdGbE3oZJ+WCKf8Dmu7VWLcmRJGc6RCzBgG31DLIyai9WAoEhYRgIHpt/BCRMrnXLbGWGPQuBUrnF0TA=="], + "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], - "detective-typescript": ["detective-typescript@14.0.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "^8.23.0", "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" }, "peerDependencies": { "typescript": "^5.4.4" } }, "sha512-pgN43/80MmWVSEi5LUuiVvO/0a9ss5V7fwVfrJ4QzAQRd3cwqU1SfWGXJFcNKUqoD5cS+uIovhw5t/0rSeC5Mw=="], + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], - "detective-vue2": ["detective-vue2@2.2.0", "", { "dependencies": { "@dependents/detective-less": "^5.0.1", "@vue/compiler-sfc": "^3.5.13", "detective-es6": "^5.0.1", "detective-sass": "^6.0.1", "detective-scss": "^5.0.1", "detective-stylus": "^5.0.1", "detective-typescript": "^14.0.0" }, "peerDependencies": { "typescript": "^5.4.4" } }, "sha512-sVg/t6O2z1zna8a/UIV6xL5KUa2cMTQbdTIIvqNM0NIPswp52fe43Nwmbahzj3ww4D844u/vC2PYfiGLvD3zFA=="], + "direction": ["direction@2.0.1", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="], - "deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="], + "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], - "devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="], + "dns-packet": ["dns-packet@5.6.1", "", { "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" } }, "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw=="], - "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], - "dfa": ["dfa@1.2.0", "", {}, "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="], + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], - "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], - "diff3": ["diff3@0.0.3", "", {}, "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g=="], + "dompurify": ["dompurify@3.3.1", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q=="], - "direction": ["direction@2.0.1", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="], + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + "dot-case": ["dot-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w=="], - "dot-prop": ["dot-prop@9.0.0", "", { "dependencies": { "type-fest": "^4.18.2" } }, "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ=="], + "dot-prop": ["dot-prop@8.0.2", "", { "dependencies": { "type-fest": "^3.8.0" } }, "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ=="], - "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], "drizzle-kit": ["drizzle-kit@0.30.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA=="], @@ -1511,49 +2330,61 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "duplexer": ["duplexer@0.1.2", "", {}, "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], + + "editorconfig": ["editorconfig@1.0.4", "", { "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", "minimatch": "9.0.1", "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q=="], + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.193", "", {}, "sha512-eePuBZXM9OVCwfYUhd2OzESeNGnWmLyeu0XAEjf7xjijNjHFdeJSzuRUGN4ueT2tEYo5YqjHramKEFxz67p3XA=="], + "electron-to-chromium": ["electron-to-chromium@1.5.259", "", {}, "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ=="], - "emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], - "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], - "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], + "engine.io-client": ["engine.io-client@6.6.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw=="], - "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], + + "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], - "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], - "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], + "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], + + "es-array-method-boxes-properly": ["es-array-method-boxes-properly@1.0.0", "", {}, "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + "es-get-iterator": ["es-get-iterator@1.1.3", "", { "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", "has-symbols": "^1.0.3", "is-arguments": "^1.1.1", "is-map": "^2.0.2", "is-set": "^2.0.2", "is-string": "^1.0.7", "isarray": "^2.0.5", "stop-iteration-iterator": "^1.0.0" } }, "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw=="], + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], - "esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="], + "esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], + + "esbuild-plugin-copy": ["esbuild-plugin-copy@2.1.1", "", { "dependencies": { "chalk": "^4.1.2", "chokidar": "^3.5.3", "fs-extra": "^10.0.1", "globby": "^11.0.3" }, "peerDependencies": { "esbuild": ">= 0.14.0" } }, "sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -1561,18 +2392,10 @@ "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], - "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - - "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], - "esprima-extract-comments": ["esprima-extract-comments@1.1.0", "", { "dependencies": { "esprima": "^4.0.0" } }, "sha512-sBQUnvJwpeE9QnPrxh7dpI/dp67erYG4WXEAreAMoelPRpMR7NWb4YtwRPn9b+H1uLQKl/qS8WYmyaljTpjIsw=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="], "estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-walker": "^3.0.0" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="], @@ -1587,44 +2410,40 @@ "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], - "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], - "events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="], + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], - "eventsource-parser": ["eventsource-parser@3.0.3", "", {}, "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA=="], + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], - "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + "execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], - "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], + "exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="], - "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], - "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], - "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], + "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], "expressive-code": ["expressive-code@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3", "@expressive-code/plugin-frames": "^0.41.3", "@expressive-code/plugin-shiki": "^0.41.3", "@expressive-code/plugin-text-markers": "^0.41.3" } }, "sha512-YLnD62jfgBZYrXIPQcJ0a51Afv9h8VlWqEGK9uU2T5nL/5rb8SnA86+7+mgCZe5D34Tff5RNEA5hjNVJYHzrFg=="], - "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], "extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], - "extract-comments": ["extract-comments@1.1.0", "", { "dependencies": { "esprima-extract-comments": "^1.1.0", "parse-code-context": "^1.0.0" } }, "sha512-dzbZV2AdSSVW/4E7Ti5hZdHWbA+Z80RJsJhr5uiL10oyjl/gy7/o+HI1HwK4/WSZhlq4SNKU3oUzXlM13Qx02Q=="], - - "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], - "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], @@ -1633,39 +2452,33 @@ "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], "fast-xml-parser": ["fast-xml-parser@4.4.1", "", { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw=="], "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], - - "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="], - - "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], - "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], + "file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "filter-obj": ["filter-obj@6.1.0", "", {}, "sha512-xdMtCAODmPloU9qtmPcdBV9Kd27NtMse+4ayThxqIHUES5Z2S6bGpap5PpdmNM56ub7y3i1eyr+vJJIIgWGKmA=="], + "finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="], - "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], + "find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="], - "find-up": ["find-up@6.3.0", "", { "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" } }, "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw=="], + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], - "find-up-simple": ["find-up-simple@1.0.1", "", {}, "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ=="], + "finity": ["finity@0.5.4", "", {}, "sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA=="], "flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="], - "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], - "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], - "fontace": ["fontace@0.3.0", "", { "dependencies": { "@types/fontkit": "^2.0.8", "fontkit": "^2.0.4" } }, "sha512-czoqATrcnxgWb/nAkfyIrRp6Q8biYj7nGnL6zfhTcX+JKKpWHFBnb8uNMw/kZr7u++3Y3wYSYoZgHkCcsuBpBg=="], + "fontace": ["fontace@0.3.1", "", { "dependencies": { "@types/fontkit": "^2.0.8", "fontkit": "^2.0.4" } }, "sha512-9f5g4feWT1jWT8+SbL85aLIRLIXUaDygaM2xPXRmzPYxrOMNok79Lr3FGJoKVNKibE0WCunNiEVG2mwuE+2qEg=="], "fontkit": ["fontkit@2.0.4", "", { "dependencies": { "@swc/helpers": "^0.5.12", "brotli": "^1.3.2", "clone": "^2.1.2", "dfa": "^1.2.0", "fast-deep-equal": "^3.1.3", "restructure": "^3.0.0", "tiny-inflate": "^1.0.3", "unicode-properties": "^1.4.0", "unicode-trie": "^2.0.0" } }, "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g=="], @@ -1673,74 +2486,112 @@ "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "form-data": ["form-data@4.0.5", "", { "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" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], + + "formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="], + "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], - "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], - "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + "framer-motion": ["framer-motion@8.5.5", "", { "dependencies": { "@motionone/dom": "^10.15.3", "hey-listen": "^1.0.8", "tslib": "^2.4.0" }, "optionalDependencies": { "@emotion/is-prop-valid": "^0.8.2" }, "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" } }, "sha512-5IDx5bxkjWHWUF3CVJoSyUVOtrbAxtzYBBowRE2uYI/6VYhkEBD+rbTHEGuUmbGHRj6YqqSfoG7Aa1cLyWCrBA=="], - "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "gel": ["gel@2.1.1", "", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw=="], + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "fuzzysort": ["fuzzysort@3.1.0", "", {}, "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ=="], - "get-amd-module-type": ["get-amd-module-type@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" } }, "sha512-MtjsmYiCXcYDDrGqtNbeIYdAl85n+5mSv2r3FbzER/YV3ZILw4HNNIw34HuV5pyl0jzs6GFYU1VHVEefhgcNHQ=="], + "gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="], + + "gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="], + + "gel": ["gel@2.2.0", "", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-q0ma7z2swmoamHQusey8ayo8+ilVdzDt4WTxSPzq/yRqvucWRfymRVMvNgmSC0XK7eNjjEZEcplxpgaNojKdmQ=="], + + "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + + "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - "get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="], + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], - "get-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="], + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + + "get-port": ["get-port@7.1.0", "", {}, "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + "get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - "get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="], + "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], - "giget": ["giget@1.2.5", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.5.4", "pathe": "^2.0.3", "tar": "^6.2.1" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug=="], + "ghostty-web": ["ghostty-web@0.3.0", "", {}, "sha512-SAdSHWYF20GMZUB0n8kh1N6Z4ljMnuUqT8iTB2n5FAPswEV10MejEpLlhW/769GL5+BQa1NYwEg9y/XCckV5+A=="], - "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], + + "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], - "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], - "globby": ["globby@14.1.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.3", "ignore": "^7.0.3", "path-type": "^6.0.0", "slash": "^5.1.0", "unicorn-magic": "^0.3.0" } }, "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA=="], + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], - "gonzales-pe": ["gonzales-pe@4.3.0", "", { "dependencies": { "minimist": "^1.2.5" }, "bin": { "gonzales": "bin/gonzales.js" } }, "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ=="], + "globby": ["globby@11.0.4", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.1.1", "ignore": "^5.1.4", "merge2": "^1.3.0", "slash": "^3.0.0" } }, "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg=="], - "google-protobuf": ["google-protobuf@3.21.4", "", {}, "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ=="], + "google-auth-library": ["google-auth-library@10.5.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" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="], - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], - "got": ["got@11.8.6", "", { "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" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "graphql": ["graphql@16.12.0", "", {}, "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ=="], + + "graphql-request": ["graphql-request@6.1.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", "cross-fetch": "^3.1.5" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw=="], + "gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="], - "gzip-size": ["gzip-size@7.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA=="], + "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], + + "h3": ["h3@2.0.1-rc.4", "", { "dependencies": { "rou3": "^0.7.8", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-vZq8pEUp6THsXKXrUXX44eOqfChic2wVQ1GlSzQCBr7DeFBkfIZAo2WyNND4GSv54TAa0E4LYIK73WSPdgKUgw=="], - "h3": ["h3@1.15.3", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.4", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.0", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ=="], + "happy-dom": ["happy-dom@20.0.11", "", { "dependencies": { "@types/node": "^20.0.0", "@types/whatwg-mimetype": "^3.0.2", "whatwg-mimetype": "^3.0.0" } }, "sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g=="], - "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], @@ -1789,71 +2640,67 @@ "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], - "hono": ["hono@4.7.10", "", {}, "sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ=="], + "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], - "hono-openapi": ["hono-openapi@0.4.8", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "valibot", "zod", "zod-openapi"] }, "sha512-LYr5xdtD49M7hEAduV1PftOMzuT8ZNvkyWfh1DThkLsIr4RkvDb12UxgIiFbwrJB6FLtFXLoOZL9x4IeDk2+VA=="], + "hey-listen": ["hey-listen@1.0.8", "", {}, "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="], - "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], + "hono": ["hono@4.10.7", "", {}, "sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw=="], - "hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], + "hono-openapi": ["hono-openapi@1.1.2", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-toUcO60MftRBxqcVyxsHNYs2m4vf4xkQaiARAucQx3TiBPDtMNNkoh+C4I1vAretQZiGyaLOZNWn1YxfSyUA5g=="], "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="], "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], + "html-minifier-terser": ["html-minifier-terser@7.2.0", "", { "dependencies": { "camel-case": "^4.1.2", "clean-css": "~5.3.2", "commander": "^10.0.0", "entities": "^4.4.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", "terser": "^5.15.1" }, "bin": { "html-minifier-terser": "cli.js" } }, "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA=="], + "html-to-image": ["html-to-image@1.11.13", "", {}, "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg=="], + "html-to-text": ["html-to-text@9.0.5", "", { "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", "dom-serializer": "^2.0.0", "htmlparser2": "^8.0.2", "selderee": "^0.11.0" } }, "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg=="], + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], "html-whitespace-sensitive-tag-names": ["html-whitespace-sensitive-tag-names@3.0.1", "", {}, "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA=="], + "htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="], + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], - "http-proxy": ["http-proxy@1.18.1", "", { "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ=="], - "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - "http-shutdown": ["http-shutdown@1.2.2", "", {}, "sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw=="], - - "http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="], - "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "httpxy": ["httpxy@0.1.7", "", {}, "sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ=="], + "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], - "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], + + "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], "ieee754": ["ieee754@1.1.13", "", {}, "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="], - "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "ignore-walk": ["ignore-walk@6.0.5", "", { "dependencies": { "minimatch": "^9.0.0" } }, "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A=="], + "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "import-in-the-middle": ["import-in-the-middle@1.14.2", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw=="], + "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="], - "import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="], + "import-local": ["import-local@3.2.0", "", { "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA=="], - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - - "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], - - "index-to-position": ["index-to-position@1.1.0", "", {}, "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg=="], + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "ini": ["ini@2.0.0", "", {}, "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA=="], + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], - "ioredis": ["ioredis@5.7.0", "", { "dependencies": { "@ioredis/commands": "^1.3.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g=="], + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], - "ip-address": ["ip-address@9.0.5", "", { "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" } }, "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g=="], + "ioredis": ["ioredis@5.8.2", "", { "dependencies": { "@ioredis/commands": "1.4.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q=="], "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -1865,58 +2712,90 @@ "is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="], - "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], - "is-builtin-module": ["is-builtin-module@3.2.1", "", { "dependencies": { "builtin-modules": "^3.3.0" } }, "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A=="], + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="], "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + "is-electron": ["is-electron@2.2.2", "", {}, "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="], + "is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], + "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + "is-in-ssh": ["is-in-ssh@1.0.0", "", {}, "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw=="], + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], - "is-lambda": ["is-lambda@1.0.1", "", {}, "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="], + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], - "is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="], + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-path-inside": ["is-path-inside@4.0.0", "", {}, "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA=="], + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], - "is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="], + "is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="], "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-stream": ["is-stream@1.1.0", "", {}, "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], - "is-url": ["is-url@1.2.4", "", {}, "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="], + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], - "is-url-superb": ["is-url-superb@4.0.0", "", {}, "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA=="], + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], "is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="], + "is-whitespace": ["is-whitespace@0.3.0", "", {}, "sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg=="], + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], "is64bit": ["is64bit@2.0.0", "", { "dependencies": { "system-architecture": "^0.1.0" } }, "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw=="], @@ -1925,53 +2804,61 @@ "isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - "isomorphic-git": ["isomorphic-git@1.32.1", "", { "dependencies": { "async-lock": "^1.4.1", "clean-git-ref": "^2.0.1", "crc-32": "^1.2.0", "diff3": "0.0.3", "ignore": "^5.1.4", "minimisted": "^2.0.0", "pako": "^1.0.10", "path-browserify": "^1.0.1", "pify": "^4.0.1", "readable-stream": "^3.4.0", "sha.js": "^2.4.9", "simple-get": "^4.0.1" }, "bin": { "isogit": "cli.cjs" } }, "sha512-NZCS7qpLkCZ1M/IrujYBD31sM6pd/fMVArK4fz4I7h6m0rUW2AsYU7S7zXeABuHL6HIfW6l53b4UQ/K441CQjg=="], + "isomorphic-ws": ["isomorphic-ws@5.0.0", "", { "peerDependencies": { "ws": "*" } }, "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw=="], + + "iterate-iterator": ["iterate-iterator@1.0.2", "", {}, "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw=="], + + "iterate-value": ["iterate-value@1.0.2", "", { "dependencies": { "es-get-iterator": "^1.0.2", "iterate-iterator": "^1.0.1" } }, "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="], - "jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="], + "jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "jmespath": ["jmespath@0.16.0", "", {}, "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw=="], "jose": ["jose@6.0.11", "", {}, "sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg=="], + "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], + "js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="], + "js-beautify": ["js-beautify@1.15.4", "", { "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", "glob": "^10.4.2", "js-cookie": "^3.0.5", "nopt": "^7.2.1" }, "bin": { "css-beautify": "js/bin/css-beautify.js", "html-beautify": "js/bin/html-beautify.js", "js-beautify": "js/bin/js-beautify.js" } }, "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA=="], + + "js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - "jsbn": ["jsbn@1.1.0", "", {}, "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="], - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - - "json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="], + "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], - "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="], - "json-schema-walker": ["json-schema-walker@2.0.0", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.1.0", "clone": "^2.1.2" } }, "sha512-nXN2cMky0Iw7Af28w061hmxaPDaML5/bQD9nwm1lOoIKEGjHcRGxqWe4MfrkYThYAPjSUhmsp4bJNoLAyVn9Xw=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], - "junk": ["junk@4.0.1", "", {}, "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ=="], + "jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="], - "just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="], + "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], - "just-diff-apply": ["just-diff-apply@5.5.0", "", {}, "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw=="], + "jws": ["jws@4.0.0", "", { "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="], - "jwt-decode": ["jwt-decode@4.0.0", "", {}, "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA=="], + "jwt-decode": ["jwt-decode@3.1.2", "", {}, "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="], - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + "katex": ["katex@0.16.27", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-aeQoDkuRWSqQN6nSvVCEFvfXdqo1OQiCmmW1kc9xSdjutPv7BGO7pqY9sQRJpMOGrEdfDgF2TfRXe5eUAD2Waw=="], "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], @@ -1979,64 +2866,98 @@ "klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="], - "knitwork": ["knitwork@1.2.0", "", {}, "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg=="], - - "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], - - "lambda-local": ["lambda-local@2.2.0", "", { "dependencies": { "commander": "^10.0.1", "dotenv": "^16.3.1", "winston": "^3.10.0" }, "bin": { "lambda-local": "build/cli.js" } }, "sha512-bPcgpIXbHnVGfI/omZIlgucDqlf4LrsunwoKue5JdZeGybt8L6KyJz2Zu19ffuZwIwLj2NAI2ZyaqNT6/cetcg=="], - "lang-map": ["lang-map@0.4.0", "", { "dependencies": { "language-map": "^1.1.0" } }, "sha512-oiSqZIEUnWdFeDNsp4HId4tAxdFbx5iMBOwA3666Fn2L8Khj8NiD9xRvMsGmKXopPVkaDFtSv3CJOmXFUB0Hcg=="], "language-map": ["language-map@1.5.0", "", {}, "sha512-n7gFZpe+DwEAX9cXVTw43i3wiudWDDtSn28RmdnS/HCPr284dQI/SztsamWanRr75oSlKSaGbV2nmWCTzGCoVg=="], "lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="], - "listhen": ["listhen@1.9.0", "", { "dependencies": { "@parcel/watcher": "^2.4.1", "@parcel/watcher-wasm": "^2.4.1", "citty": "^0.1.6", "clipboardy": "^4.0.0", "consola": "^3.2.3", "crossws": ">=0.2.0 <0.4.0", "defu": "^6.1.4", "get-port-please": "^3.1.2", "h3": "^1.12.0", "http-shutdown": "^1.2.2", "jiti": "^2.1.2", "mlly": "^1.7.1", "node-forge": "^1.3.1", "pathe": "^1.1.2", "std-env": "^3.7.0", "ufo": "^1.5.4", "untun": "^0.1.3", "uqr": "^0.1.2" }, "bin": { "listen": "bin/listhen.mjs", "listhen": "bin/listhen.mjs" } }, "sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg=="], + "leac": ["leac@0.6.0", "", {}, "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="], - "local-pkg": ["local-pkg@1.1.1", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.0.1", "quansync": "^0.2.8" } }, "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg=="], + "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="], - "locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="], - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="], - "lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="], - "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="], - "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="], + + "lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], + "lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="], + "lodash.isarguments": ["lodash.isarguments@3.1.0", "", {}, "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="], - "logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], + "lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="], + + "lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="], + + "lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="], + + "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], + + "lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="], + + "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + + "loglevelnext": ["loglevelnext@6.0.0", "", {}, "sha512-FDl1AI2sJGjHHG3XKJd6sG3/6ncgiGCQ0YkW46nxe7SfqQq6hujd9CvFXIXtkGBUN83KPZ2KSOJK8q5P0bSSRQ=="], "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], - "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="], + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="], + + "lru_map": ["lru_map@0.4.1", "", {}, "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg=="], + "luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="], - "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], - "make-fetch-happen": ["make-fetch-happen@13.0.1", "", { "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", "http-cache-semantics": "^4.1.1", "is-lambda": "^1.0.1", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" } }, "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA=="], - "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], - "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], + "marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="], + + "marked-katex-extension": ["marked-katex-extension@5.1.6", "", { "peerDependencies": { "katex": ">=0.16 <0.17", "marked": ">=4 <18" } }, "sha512-vYpLXwmlIDKILIhJtiRTgdyZRn5sEYdFBuTmbpjD7lbCIzg0/DWyK3HXIntN3Tp8zV6hvOUgpZNLWRCgWVc24A=="], "marked-shiki": ["marked-shiki@1.2.1", "", { "peerDependencies": { "marked": ">=7.0.0", "shiki": ">=1.0.0" } }, "sha512-yHxYQhPY5oYaIRnROn98foKhuClark7M373/VpLxiy5TrDu9Jd/LsMwo8w+U91Up4oDb9IXFrP0N1MFRz8W/DQ=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "md-to-react-email": ["md-to-react-email@5.0.0", "", { "dependencies": { "marked": "7.0.4" }, "peerDependencies": { "react": "18.x" } }, "sha512-GdBrBUbAAJHypnuyofYGfVos8oUslxHx69hs3CW9P0L8mS1sT6GnJuMBTlz/Fw+2widiwdavcu9UwyLF/BzZ4w=="], + "mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="], "mdast-util-directive": ["mdast-util-directive@3.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q=="], @@ -2075,19 +2996,17 @@ "mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="], - "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], "merge-anything": ["merge-anything@5.1.7", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ=="], - "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], - - "merge-options": ["merge-options@3.0.4", "", { "dependencies": { "is-plain-obj": "^2.1.0" } }, "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ=="], + "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "micro-api-client": ["micro-api-client@3.3.0", "", {}, "sha512-y0y6CUB9RLVsy3kfgayU28746QrNMpSm9O/AYGNsBgOkJr/X/Jk0VLGoO8Ude7Bpa8adywzF+MzXNZRFRsNPhg=="], + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], @@ -2163,117 +3082,83 @@ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - "mime": ["mime@4.0.7", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ=="], + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], - "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - - "miniflare": ["miniflare@4.20250730.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^7.10.0", "workerd": "1.20250730.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-avGXBStHQSqcJr8ra1mJ3/OQvnLZ49B1uAILQapAha1DHNZZvXWLIgUVre/WGY6ZOlNGFPh5CJ+dXLm4yuV3Jw=="], + "miniflare": ["miniflare@4.20251118.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251118.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ=="], "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minimisted": ["minimisted@2.0.1", "", { "dependencies": { "minimist": "^1.2.5" } }, "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA=="], - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], - "minipass-fetch": ["minipass-fetch@3.0.5", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg=="], + "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], - "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], - - "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], - - "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], - - "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], - "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="], - "mlly": ["mlly@1.7.4", "", { "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw=="], + "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], - "module-definition": ["module-definition@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" }, "bin": { "module-definition": "bin/cli.js" } }, "sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g=="], + "mysql2": ["mysql2@3.14.4", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-Cs/jx3WZPNrYHVz+Iunp9ziahaG5uFMvD2R8Zlmc194AqXNxt9HBNu7ZsPYrUtmJsF0egETCWIdMIYAwOGjL1w=="], - "module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], - "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + "named-placeholders": ["named-placeholders@1.1.3", "", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="], - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "nanoevents": ["nanoevents@7.0.1", "", {}, "sha512-o6lpKiCxLeijK4hgsqfR6CNToPyRU3keKyyI6uwuHRvpRTbZ0wXw51WRgyldVugZqoJfkGFrjrIenYH3bfEO3Q=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], - - "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - - "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], - "netlify": ["netlify@13.3.5", "", { "dependencies": { "@netlify/open-api": "^2.37.0", "lodash-es": "^4.17.21", "micro-api-client": "^3.3.0", "node-fetch": "^3.0.0", "p-wait-for": "^5.0.0", "qs": "^6.9.6" } }, "sha512-Nc3loyVASW59W+8fLDZT1lncpG7llffyZ2o0UQLx/Fr20i7P8oP+lE7+TEcFvXj9IUWU6LjB9P3BH+iFGyp+mg=="], + "nf3": ["nf3@0.1.12", "", {}, "sha512-qbMXT7RTGh74MYWPeqTIED8nDW70NXOULVHpdWcdZ7IVHVnAsMV9fNugSNnvooipDc1FMOzpis7T9nXJEbJhvQ=="], - "nitropack": ["nitropack@2.12.4", "", { "dependencies": { "@cloudflare/kv-asset-handler": "^0.4.0", "@netlify/functions": "^3.1.10", "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-commonjs": "^28.0.6", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-replace": "^6.0.2", "@rollup/plugin-terser": "^0.4.4", "@vercel/nft": "^0.29.4", "archiver": "^7.0.1", "c12": "^3.1.0", "chokidar": "^4.0.3", "citty": "^0.1.6", "compatx": "^0.2.0", "confbox": "^0.2.2", "consola": "^3.4.2", "cookie-es": "^2.0.0", "croner": "^9.1.0", "crossws": "^0.3.5", "db0": "^0.3.2", "defu": "^6.1.4", "destr": "^2.0.5", "dot-prop": "^9.0.0", "esbuild": "^0.25.6", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", "exsolve": "^1.0.7", "globby": "^14.1.0", "gzip-size": "^7.0.0", "h3": "^1.15.3", "hookable": "^5.5.3", "httpxy": "^0.1.7", "ioredis": "^5.6.1", "jiti": "^2.4.2", "klona": "^2.0.6", "knitwork": "^1.2.0", "listhen": "^1.9.0", "magic-string": "^0.30.17", "magicast": "^0.3.5", "mime": "^4.0.7", "mlly": "^1.7.4", "node-fetch-native": "^1.6.6", "node-mock-http": "^1.0.1", "ofetch": "^1.4.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "pretty-bytes": "^6.1.1", "radix3": "^1.1.2", "rollup": "^4.45.0", "rollup-plugin-visualizer": "^6.0.3", "scule": "^1.3.0", "semver": "^7.7.2", "serve-placeholder": "^2.0.2", "serve-static": "^2.2.0", "source-map": "^0.7.4", "std-env": "^3.9.0", "ufo": "^1.6.1", "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", "unctx": "^2.4.1", "unenv": "^2.0.0-rc.18", "unimport": "^5.1.0", "unplugin-utils": "^0.2.4", "unstorage": "^1.16.1", "untyped": "^2.0.0", "unwasm": "^0.3.9", "youch": "4.1.0-beta.8", "youch-core": "^0.3.3" }, "peerDependencies": { "xml2js": "^0.6.2" }, "optionalPeers": ["xml2js"], "bin": { "nitro": "dist/cli/index.mjs", "nitropack": "dist/cli/index.mjs" } }, "sha512-MPmPRJWTeH03f/NmpN4q3iI3Woik4uaaWIoX34W3gMJiW06Vm1te/lPzuu5EXpXOK7Q2m3FymGMPXcExqih96Q=="], + "nitro": ["nitro@3.0.1-alpha.1", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.1", "db0": "^0.3.4", "h3": "2.0.1-rc.5", "jiti": "^2.6.1", "nf3": "^0.1.10", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "oxc-minify": "^0.96.0", "oxc-transform": "^0.96.0", "srvx": "^0.9.5", "undici": "^7.16.0", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.4" }, "peerDependencies": { "rolldown": "*", "rollup": "^4", "vite": "^7", "xml2js": "^0.6.2" }, "optionalPeers": ["rolldown", "rollup", "vite", "xml2js"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-U4AxIsXxdkxzkFrK0XAw0e5Qbojk8jQ50MjjRBtBakC4HurTtQoiZvF+lSe382jhuQZCfAyywGWOFa9QzXLFaw=="], "nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="], - "node-abi": ["node-abi@3.75.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg=="], + "no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="], - "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="], - - "node-forge": ["node-forge@1.3.1", "", {}, "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="], - - "node-gyp": ["node-gyp@10.3.1", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "glob": "^10.3.10", "graceful-fs": "^4.2.6", "make-fetch-happen": "^13.0.0", "nopt": "^7.0.0", "proc-log": "^4.1.0", "semver": "^7.3.5", "tar": "^6.2.1", "which": "^4.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], - "node-mock-http": ["node-mock-http@1.0.2", "", {}, "sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g=="], + "node-html-parser": ["node-html-parser@7.0.1", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA=="], - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + "node-mock-http": ["node-mock-http@1.0.3", "", {}, "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog=="], - "node-source-walk": ["node-source-walk@7.0.1", "", { "dependencies": { "@babel/parser": "^7.26.7" } }, "sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg=="], + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "nopt": ["nopt@7.2.1", "", { "dependencies": { "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w=="], - "normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="], - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - "normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="], - - "npm-bundled": ["npm-bundled@3.0.1", "", { "dependencies": { "npm-normalize-package-bin": "^3.0.0" } }, "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ=="], - - "npm-install-checks": ["npm-install-checks@6.3.0", "", { "dependencies": { "semver": "^7.1.1" } }, "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw=="], - - "npm-normalize-package-bin": ["npm-normalize-package-bin@3.0.1", "", {}, "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ=="], - - "npm-package-arg": ["npm-package-arg@11.0.3", "", { "dependencies": { "hosted-git-info": "^7.0.0", "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" } }, "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw=="], + "normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="], - "npm-packlist": ["npm-packlist@8.0.2", "", { "dependencies": { "ignore-walk": "^6.0.4" } }, "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA=="], - - "npm-pick-manifest": ["npm-pick-manifest@9.1.0", "", { "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", "npm-package-arg": "^11.0.0", "semver": "^7.3.5" } }, "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA=="], - - "npm-registry-fetch": ["npm-registry-fetch@17.1.0", "", { "dependencies": { "@npmcli/redact": "^2.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", "proc-log": "^4.0.0" } }, "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA=="], - - "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], - "nypm": ["nypm@0.5.4", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "tinyexec": "^0.3.2", "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA=="], + "nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -2281,23 +3166,29 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - "ofetch": ["ofetch@1.4.1", "", { "dependencies": { "destr": "^2.0.3", "node-fetch-native": "^1.6.4", "ufo": "^1.5.4" } }, "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw=="], + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], - "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], - "oidc-token-hash": ["oidc-token-hash@5.1.0", "", {}, "sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA=="], + "ofetch": ["ofetch@2.0.0-alpha.3", "", {}, "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "oidc-token-hash": ["oidc-token-hash@5.2.0", "", {}, "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw=="], + + "omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], - - "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], "oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="], - "oniguruma-to-es": ["oniguruma-to-es@4.3.3", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg=="], + "oniguruma-to-es": ["oniguruma-to-es@4.3.4", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA=="], "open": ["open@10.1.2", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw=="], @@ -2311,186 +3202,198 @@ "openid-client": ["openid-client@5.6.4", "", { "dependencies": { "jose": "^4.15.4", "lru-cache": "^6.0.0", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.3" } }, "sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA=="], - "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], + "opentui-spinner": ["opentui-spinner@0.0.6", "", { "dependencies": { "cli-spinners": "^3.3.0" }, "peerDependencies": { "@opentui/core": "^0.1.49", "@opentui/react": "^0.1.49", "@opentui/solid": "^0.1.49", "typescript": "^5" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-xupLOeVQEAXEvVJCvHkfX6fChDWmJIPHe5jyUrVb8+n4XVTX8mBNhitFfB9v2ZbkC1H2UwPab/ElePHoW37NcA=="], - "p-event": ["p-event@6.0.1", "", { "dependencies": { "p-timeout": "^6.1.2" } }, "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w=="], + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "oxc-minify": ["oxc-minify@0.96.0", "", { "optionalDependencies": { "@oxc-minify/binding-android-arm64": "0.96.0", "@oxc-minify/binding-darwin-arm64": "0.96.0", "@oxc-minify/binding-darwin-x64": "0.96.0", "@oxc-minify/binding-freebsd-x64": "0.96.0", "@oxc-minify/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-minify/binding-linux-arm-musleabihf": "0.96.0", "@oxc-minify/binding-linux-arm64-gnu": "0.96.0", "@oxc-minify/binding-linux-arm64-musl": "0.96.0", "@oxc-minify/binding-linux-riscv64-gnu": "0.96.0", "@oxc-minify/binding-linux-s390x-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-musl": "0.96.0", "@oxc-minify/binding-wasm32-wasi": "0.96.0", "@oxc-minify/binding-win32-arm64-msvc": "0.96.0", "@oxc-minify/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dXeeGrfPJJ4rMdw+NrqiCRtbzVX2ogq//R0Xns08zql2HjV3Zi2SBJ65saqfDaJzd2bcHqvGWH+M44EQCHPAcA=="], + + "oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="], + + "p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="], + + "p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="], "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="], - "p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="], + "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], - "p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="], + "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="], - "p-queue": ["p-queue@8.1.0", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw=="], + "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="], - "p-wait-for": ["p-wait-for@5.0.2", "", { "dependencies": { "p-timeout": "^6.0.0" } }, "sha512-lwx6u1CotQYPVju77R+D0vFomni/AqRfqLmqQ8hekklqZ6gAY9rONh7lBQ0uxWMkC2AuX9b2DVAl8To0NyP1JA=="], + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - "package-manager-detector": ["package-manager-detector@1.3.0", "", {}, "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ=="], + "package-manager-detector": ["package-manager-detector@1.5.0", "", {}, "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw=="], - "pacote": ["pacote@18.0.6", "", { "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.0", "@npmcli/run-script": "^8.0.0", "cacache": "^18.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^11.0.0", "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^17.0.0", "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, "bin": { "pacote": "bin/index.js" } }, "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A=="], + "pagefind": ["pagefind@1.4.0", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.4.0", "@pagefind/darwin-x64": "1.4.0", "@pagefind/freebsd-x64": "1.4.0", "@pagefind/linux-arm64": "1.4.0", "@pagefind/linux-x64": "1.4.0", "@pagefind/windows-x64": "1.4.0" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g=="], - "pagefind": ["pagefind@1.3.0", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.3.0", "@pagefind/darwin-x64": "1.3.0", "@pagefind/linux-arm64": "1.3.0", "@pagefind/linux-x64": "1.3.0", "@pagefind/windows-x64": "1.3.0" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-8KPLGT5g9s+olKMRTU9LFekLizkVIu9tes90O1/aigJ0T5LmyPqTzGJrETnSw3meSYg58YH7JTzhTTW/3z6VAw=="], + "pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="], - "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + "param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="], - "parse-code-context": ["parse-code-context@1.0.0", "", {}, "sha512-OZQaqKaQnR21iqhlnPfVisFjBWjhnMl5J9MgbP8xC+EwoVqbXrq78lp+9Zb3ahmLzrIX5Us/qbvBnaS3hkH6OA=="], + "parse-bmfont-ascii": ["parse-bmfont-ascii@1.0.6", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="], - "parse-conflict-json": ["parse-conflict-json@3.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^3.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw=="], + "parse-bmfont-binary": ["parse-bmfont-binary@1.0.6", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="], - "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], - - "parse-gitignore": ["parse-gitignore@2.0.0", "", {}, "sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog=="], + "parse-bmfont-xml": ["parse-bmfont-xml@1.1.6", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="], - "parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="], + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], "parse-latin": ["parse-latin@7.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", "nlcst-to-string": "^4.0.0", "unist-util-modify-children": "^4.0.0", "unist-util-visit-children": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ=="], "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], + + "parseley": ["parseley@0.12.1", "", { "dependencies": { "leac": "^0.6.0", "peberminta": "^0.9.0" } }, "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], - "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="], + + "pascal-case": ["pascal-case@3.1.2", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="], - "path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], - "path-type": ["path-type@6.0.0", "", {}, "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ=="], + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], - "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + "peberminta": ["peberminta@0.9.0", "", {}, "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ=="], - "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], + "peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="], - "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + "perfect-debounce": ["perfect-debounce@2.0.0", "", {}, "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow=="], - "pg-protocol": ["pg-protocol@1.10.3", "", {}, "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ=="], - - "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], + "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], - "pkce-challenge": ["pkce-challenge@5.0.0", "", {}, "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="], + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], - "pkg-dir": ["pkg-dir@7.0.0", "", { "dependencies": { "find-up": "^6.3.0" } }, "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA=="], + "pixelmatch": ["pixelmatch@5.3.0", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="], - "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], - "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], - "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], + "pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="], - "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "planck": ["planck@1.4.2", "", { "peerDependencies": { "stage-js": "^1.0.0-alpha.12" } }, "sha512-mNbhnV3g8X2rwGxzcesjmN8BDA6qfXgQxXVMkWau9MCRlQY0RLNEkyHlVp6yFy/X6qrzAXyNONCnZ1cGDLrNew=="], - "postcss-values-parser": ["postcss-values-parser@6.0.2", "", { "dependencies": { "color-name": "^1.1.4", "is-url-superb": "^4.0.0", "quote-unquote": "^1.0.0" }, "peerDependencies": { "postcss": "^8.2.9" } }, "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw=="], + "playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="], - "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], + "playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="], - "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], - "postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + "postcss-css-variables": ["postcss-css-variables@0.18.0", "", { "dependencies": { "balanced-match": "^1.0.0", "escape-string-regexp": "^1.0.3", "extend": "^3.0.1" }, "peerDependencies": { "postcss": "^8.2.6" } }, "sha512-lYS802gHbzn1GI+lXvy9MYIYDuGnl1WB4FTKoqMQqJ3Mab09A7a/1wZvGTkCEZJTM8mSbIyb1mJYn8f0aPye0Q=="], - "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], + "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], - "precinct": ["precinct@12.2.0", "", { "dependencies": { "@dependents/detective-less": "^5.0.1", "commander": "^12.1.0", "detective-amd": "^6.0.1", "detective-cjs": "^6.0.1", "detective-es6": "^5.0.1", "detective-postcss": "^7.0.1", "detective-sass": "^6.0.1", "detective-scss": "^5.0.1", "detective-stylus": "^5.0.1", "detective-typescript": "^14.0.0", "detective-vue2": "^2.2.0", "module-definition": "^6.0.1", "node-source-walk": "^7.0.1", "postcss": "^8.5.1", "typescript": "^5.7.3" }, "bin": { "precinct": "bin/cli.js" } }, "sha512-NFBMuwIfaJ4SocE9YXPU/n4AcNSoFMVFjP72nvl3cx69j/ke61/hPOWFREVxLkFhhEGnA8ZuVfTqJBa+PK3b5w=="], + "postcss-js": ["postcss-js@4.1.0", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw=="], - "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="], + "postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="], - "pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="], + "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], - "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], + "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - "proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="], + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="], - "proggy": ["proggy@2.0.0", "", {}, "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], - "promise-all-reject-late": ["promise-all-reject-late@1.0.1", "", {}, "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw=="], + "pretty": ["pretty@2.0.0", "", { "dependencies": { "condense-newlines": "^0.2.1", "extend-shallow": "^2.0.1", "js-beautify": "^1.6.12" } }, "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w=="], - "promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="], + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], + + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], - "promise-inflight": ["promise-inflight@1.0.1", "", {}, "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], - "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], + "promise.allsettled": ["promise.allsettled@1.0.7", "", { "dependencies": { "array.prototype.map": "^1.0.5", "call-bind": "^1.0.2", "define-properties": "^1.2.0", "es-abstract": "^1.22.1", "get-intrinsic": "^1.2.1", "iterate-value": "^1.0.2" } }, "sha512-hezvKvQQmsFkOdrZfYxUxkyxl8mgFQeT259Ajj9PXdbg9VzBCWrItOev72JyWxkCD5VSSqAeHmlN3tWx4DlmsA=="], "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], - "protobufjs": ["protobufjs@7.5.3", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw=="], + "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], - "pulumi-stripe": ["pulumi-stripe@0.0.24", "", { "dependencies": { "@pulumi/pulumi": "^3.0.0" } }, "sha512-ec2Gn9IPszVZ0n9IOo5Mroik6pHM1cyJmBxWoN8XG7gFXBeJPme9tdWXy1rmWDIDyhjN5R+AKqL75X6Nar+BVQ=="], - - "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], "punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="], "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], - "quansync": ["quansync@0.2.10", "", {}, "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A=="], + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], "querystring": ["querystring@0.2.0", "", {}, "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="], + "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], - "quote-unquote": ["quote-unquote@1.0.0", "", {}, "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], - "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], + "raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], - "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], - "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + "react": ["react@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ=="], - "raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="], + "react-dom": ["react-dom@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" }, "peerDependencies": { "react": "^18.2.0" } }, "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g=="], - "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], - "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], + "react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], - "read-cmd-shim": ["read-cmd-shim@4.0.0", "", {}, "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q=="], + "react-router": ["react-router@6.16.0", "", { "dependencies": { "@remix-run/router": "1.9.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA=="], - "read-package-json-fast": ["read-package-json-fast@3.0.2", "", { "dependencies": { "json-parse-even-better-errors": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" } }, "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw=="], + "react-router-dom": ["react-router-dom@6.16.0", "", { "dependencies": { "@remix-run/router": "1.9.0", "react-router": "6.16.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg=="], - "read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="], + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], - "read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="], + "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + + "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="], "readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="], "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], - "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], @@ -2503,12 +3406,16 @@ "redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="], + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + "regex": ["regex@6.0.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA=="], "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + "rehype": ["rehype@13.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "rehype-parse": "^9.0.0", "rehype-stringify": "^10.0.0", "unified": "^11.0.0" } }, "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A=="], "rehype-autolink-headings": ["rehype-autolink-headings@7.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-is-element": "^3.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw=="], @@ -2525,11 +3432,13 @@ "rehype-stringify": ["rehype-stringify@10.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-html": "^9.0.0", "unified": "^11.0.0" } }, "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA=="], + "relateurl": ["relateurl@0.2.7", "", {}, "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="], + "remark-directive": ["remark-directive@3.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-directive": "^3.0.0", "micromark-extension-directive": "^3.0.0", "unified": "^11.0.0" } }, "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A=="], "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], - "remark-mdx": ["remark-mdx@3.1.0", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA=="], + "remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="], "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], @@ -2541,28 +3450,18 @@ "remeda": ["remeda@2.26.0", "", { "dependencies": { "type-fest": "^4.41.0" } }, "sha512-lmNNwtaC6Co4m0WTTNoZ/JlpjEqAjPZO0+czC9YVRQUpkbS4x8Hmh+Mn9HPfJfiXqUQ5IXXgSXSOB2pBKAytdA=="], - "remove-trailing-separator": ["remove-trailing-separator@1.1.0", "", {}, "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw=="], - - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - "require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="], - - "require-package-name": ["require-package-name@2.0.1", "", {}, "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q=="], + "reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="], - "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], - - "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], + "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="], - "restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="], "retext": ["retext@9.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", "retext-stringify": "^4.0.0", "unified": "^11.0.0" } }, "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA=="], @@ -2573,57 +3472,63 @@ "retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="], - "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "rollup": ["rollup@4.46.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.46.2", "@rollup/rollup-android-arm64": "4.46.2", "@rollup/rollup-darwin-arm64": "4.46.2", "@rollup/rollup-darwin-x64": "4.46.2", "@rollup/rollup-freebsd-arm64": "4.46.2", "@rollup/rollup-freebsd-x64": "4.46.2", "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", "@rollup/rollup-linux-arm-musleabihf": "4.46.2", "@rollup/rollup-linux-arm64-gnu": "4.46.2", "@rollup/rollup-linux-arm64-musl": "4.46.2", "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", "@rollup/rollup-linux-ppc64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-musl": "4.46.2", "@rollup/rollup-linux-s390x-gnu": "4.46.2", "@rollup/rollup-linux-x64-gnu": "4.46.2", "@rollup/rollup-linux-x64-musl": "4.46.2", "@rollup/rollup-win32-arm64-msvc": "4.46.2", "@rollup/rollup-win32-ia32-msvc": "4.46.2", "@rollup/rollup-win32-x64-msvc": "4.46.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg=="], + "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], - "rollup-plugin-visualizer": ["rollup-plugin-visualizer@6.0.3", "", { "dependencies": { "open": "^8.0.0", "picomatch": "^4.0.2", "source-map": "^0.7.4", "yargs": "^17.5.1" }, "peerDependencies": { "rolldown": "1.x || ^1.0.0-beta", "rollup": "2.x || 3.x || 4.x" }, "optionalPeers": ["rolldown", "rollup"], "bin": { "rollup-plugin-visualizer": "dist/bin/cli.js" } }, "sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw=="], + "rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="], + + "rou3": ["rou3@0.7.10", "", {}, "sha512-aoFj6f7MJZ5muJ+Of79nrhs9N3oLGqi2VEMe94Zbkjb6Wupha46EuoYgpWSOZlXww3bbd8ojgXTAA2mzimX5Ww=="], "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], - "run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="], + "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "s-js": ["s-js@0.4.9", "", {}, "sha512-RtpOm+cM6O0sHg6IA70wH+UC3FZcND+rccBZpBAHzlUgNO2Bm5BN+FnM8+OBxzXdwpKWFwX11JGF0MFRkhSoIQ=="], + + "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], - "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], "sax": ["sax@1.2.1", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="], - "scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="], + "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], "section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="], - "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], + "selderee": ["selderee@0.11.0", "", { "dependencies": { "parseley": "^0.12.0" } }, "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA=="], - "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], - "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], + "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], "seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="], - "seroval-plugins": ["seroval-plugins@1.3.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ=="], - - "serve-placeholder": ["serve-placeholder@2.0.2", "", { "dependencies": { "defu": "^6.1.4" } }, "sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ=="], + "seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="], "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], - "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], - "sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="], + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], - "sharp": ["sharp@0.32.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", "semver": "^7.5.4", "simple-get": "^4.0.1", "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" } }, "sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ=="], + "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -2631,9 +3536,9 @@ "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], - "shiki": ["shiki@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/engine-javascript": "3.4.2", "@shikijs/engine-oniguruma": "3.4.2", "@shikijs/langs": "3.4.2", "@shikijs/themes": "3.4.2", "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ=="], + "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="], - "shimmer": ["shimmer@1.2.1", "", {}, "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="], + "shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="], "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], @@ -2643,33 +3548,27 @@ "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - - "sigstore": ["sigstore@2.3.1", "", { "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", "@sigstore/protobuf-specs": "^0.3.2", "@sigstore/sign": "^2.3.2", "@sigstore/tuf": "^2.3.4", "@sigstore/verify": "^1.2.1" } }, "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ=="], + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], - "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], + "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], - "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="], + "simple-xml-to-json": ["simple-xml-to-json@1.2.3", "", {}, "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], - "sitemap": ["sitemap@8.0.0", "", { "dependencies": { "@types/node": "^17.0.5", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.2.4" }, "bin": { "sitemap": "dist/cli.js" } }, "sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A=="], + "sitemap": ["sitemap@8.0.2", "", { "dependencies": { "@types/node": "^17.0.5", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { "sitemap": "dist/cli.js" } }, "sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ=="], - "slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="], + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + "smol-toml": ["smol-toml@1.5.2", "", {}, "sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ=="], - "smob": ["smob@1.5.0", "", {}, "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig=="], + "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], - "smol-toml": ["smol-toml@1.4.1", "", {}, "sha512-CxdwHXyYTONGHThDbq5XdwbFsuY4wlClRGejfE2NtwUtiHYsP1QtNsHb/hnj31jKYSchztJsaA8pSQoVzkfCFg=="], + "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], - "socks": ["socks@2.8.6", "", { "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA=="], - - "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], - - "solid-js": ["solid-js@1.9.7", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw=="], + "solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="], "solid-list": ["solid-list@0.3.0", "", { "dependencies": { "@corvu/utils": "~0.4.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-t4hx/F/l8Vmq+ib9HtZYl7Z9F1eKxq3eKJTXlvcm7P7yI4Z8O7QSOOEVHb/K6DD7M0RxzVRobK/BS5aSfLRwKg=="], @@ -2679,9 +3578,11 @@ "solid-refresh": ["solid-refresh@0.6.3", "", { "dependencies": { "@babel/generator": "^7.23.6", "@babel/helper-module-imports": "^7.22.15", "@babel/types": "^7.23.6" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA=="], + "solid-stripe": ["solid-stripe@0.8.1", "", { "peerDependencies": { "@stripe/stripe-js": ">=1.44.1 <8.0.0", "solid-js": "^1.6.0" } }, "sha512-l2SkWoe51rsvk9u1ILBRWyCHODZebChSGMR6zHYJTivTRC0XWrRnNNKs5x1PYXsaIU71KYI6ov5CZB5cOtGLWw=="], + "solid-use": ["solid-use@0.9.1", "", { "peerDependencies": { "solid-js": "^1.7" } }, "sha512-UwvXDVPlrrbj/9ewG9ys5uL2IO4jSiwys2KPzK4zsnAcmEl7iDafZWW1Mo4BSEWOmQCGK6IvpmGHo1aou8iOFw=="], - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -2689,113 +3590,129 @@ "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], - "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], - - "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], - - "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], - - "spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="], - "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], - "ssri": ["ssri@10.0.6", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ=="], + "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], + + "srvx": ["srvx@0.9.6", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-5L4rT6qQqqb+xcoDoklUgCNdmzqJ6vbcDRwPVGRXewF55IJH0pqh0lQlrJ266ZWTKJ4mfeioqHQJeAYesS+RrQ=="], - "sst": ["sst@3.17.8", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.8", "sst-darwin-x64": "3.17.8", "sst-linux-arm64": "3.17.8", "sst-linux-x64": "3.17.8", "sst-linux-x86": "3.17.8", "sst-win32-arm64": "3.17.8", "sst-win32-x64": "3.17.8", "sst-win32-x86": "3.17.8" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-P/a9/ZsjtQRrTBerBMO1ODaVa5HVTmNLrQNJiYvu2Bgd0ov+vefQeHv6oima8HLlPwpDIPS2gxJk8BZrTZMfCA=="], + "sst": ["sst@3.17.23", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.23", "sst-darwin-x64": "3.17.23", "sst-linux-arm64": "3.17.23", "sst-linux-x64": "3.17.23", "sst-linux-x86": "3.17.23", "sst-win32-arm64": "3.17.23", "sst-win32-x64": "3.17.23", "sst-win32-x86": "3.17.23" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-TwKgUgDnZdc1Swe+bvCNeyO4dQnYz5cTodMpYj3jlXZdK9/KNz0PVxT1f0u5E76i1pmilXrUBL/f7iiMPw4RDg=="], - "sst-darwin-arm64": ["sst-darwin-arm64@3.17.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-50P6YRMnZVItZUfB0+NzqMww2mmm4vB3zhTVtWUtGoXeiw78g1AEnVlmS28gYXPHM1P987jTvR7EON9u9ig/Dg=="], + "sst-darwin-arm64": ["sst-darwin-arm64@3.17.23", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R6kvmF+rUideOoU7KBs2SdvrIupoE+b+Dor/eq9Uo4Dojj7KvYDZI/EDm8sSCbbcx/opiWeyNqKtlnLEdCxE6g=="], - "sst-darwin-x64": ["sst-darwin-x64@3.17.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-P0pnMHCmpkpcsxkWpilmeoD79LkbkoIcv6H0aeM9ArT/71/JBhvqH+HjMHSJCzni/9uR6er+nH5F+qol0UO6Bw=="], + "sst-darwin-x64": ["sst-darwin-x64@3.17.23", "", { "os": "darwin", "cpu": "x64" }, "sha512-WW4P1S35iYCifQXxD+sE3wuzcN+LHLpuKMaNoaBqEcWGZnH3IPaDJ7rpLF0arkDAo/z3jZmWWzOCkr0JuqJ8vQ=="], - "sst-linux-arm64": ["sst-linux-arm64@3.17.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-vun54YA/UzprCu9p8BC4rMwFU5Cj9xrHAHYLYUp/yq4H0pfmBIiQM62nsfIKizRThe/TkBFy60EEi9myf6raYA=="], + "sst-linux-arm64": ["sst-linux-arm64@3.17.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-TjtNqgIh7RlAWgPLFCAt0mXvIB+J7WjmRvIRrAdX0mXsndOiBJ/DMOgXSLVsIWHCfPj8MIEot/hWpnJgXgIeag=="], - "sst-linux-x64": ["sst-linux-x64@3.17.8", "", { "os": "linux", "cpu": "x64" }, "sha512-HqByCaLE2gEJbM20P1QRd+GqDMAiieuU53FaZA1F+AGxQi+kR82NWjrPqFcMj4dMYg8w/TWXuV+G5+PwoUmpDw=="], + "sst-linux-x64": ["sst-linux-x64@3.17.23", "", { "os": "linux", "cpu": "x64" }, "sha512-qdqJiEbYfCjZlI3F/TA6eoIU7JXVkEEI/UMILNf2JWhky0KQdCW2Xyz+wb6c0msVJCWdUM/uj+1DaiP2eXvghw=="], - "sst-linux-x86": ["sst-linux-x86@3.17.8", "", { "os": "linux", "cpu": "none" }, "sha512-bCd6QM3MejfSmdvg8I/k+aUJQIZEQJg023qmN78fv00vwlAtfECvY7tjT9E2m3LDp33pXrcRYbFOQzPu+tWFfA=="], + "sst-linux-x86": ["sst-linux-x86@3.17.23", "", { "os": "linux", "cpu": "none" }, "sha512-aGmUujIvoNlmAABEGsOgfY1rxD9koC6hN8bnTLbDI+oI/u/zjHYh50jsbL0p3TlaHpwF/lxP3xFSuT6IKp+KgA=="], - "sst-win32-arm64": ["sst-win32-arm64@3.17.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-pilx0n8gm4aHJae/vNiqIwZkWF3tdwWzD/ON7hkytw+CVSZ0FXtyFW/yO/+2u3Yw0Kj0lSWPnUqYgm/eHPLwQA=="], + "sst-win32-arm64": ["sst-win32-arm64@3.17.23", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZxdkGqYDrrZGz98rijDCN+m5yuCcwD6Bc9/6hubLsvdpNlVorUqzpg801Ec97xSK0nIC9g6pNiRyxAcsQQstUg=="], - "sst-win32-x64": ["sst-win32-x64@3.17.8", "", { "os": "win32", "cpu": "x64" }, "sha512-Jb0FVRyiOtESudF1V8ucW65PuHrx/iOHUamIO0JnbujWNHZBTRPB2QHN1dbewgkueYDaCmyS8lvuIImLwYJnzQ=="], + "sst-win32-x64": ["sst-win32-x64@3.17.23", "", { "os": "win32", "cpu": "x64" }, "sha512-yc9cor4MS49Ccy2tQCF1tf6M81yLeSGzGL+gjhUxpVKo2pN3bxl3w70eyU/mTXSEeyAmG9zEfbt6FNu4sy5cUA=="], - "sst-win32-x86": ["sst-win32-x86@3.17.8", "", { "os": "win32", "cpu": "none" }, "sha512-oVmFa/PoElQmfnGJlB0w6rPXiYuldiagO6AbrLMT/6oAnWerLQ8Uhv9tJWfMh3xtPLImQLTjxDo1v0AIzEv9QA=="], + "sst-win32-x86": ["sst-win32-x86@3.17.23", "", { "os": "win32", "cpu": "none" }, "sha512-DIp3s54IpNAfdYjSRt6McvkbEPQDMxUu6RUeRAd2C+FcTJgTloon/ghAPQBaDgu2VoVgymjcJARO/XyfKcCLOQ=="], - "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], + "stage-js": ["stage-js@1.0.0-alpha.17", "", {}, "sha512-AzlMO+t51v6cFvKZ+Oe9DJnL1OXEH5s9bEy6di5aOrUpcP7PCzI/wIeXF0u3zg0L89gwnceoKxrLId0ZpYnNXw=="], + "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], - "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], - "std-env": ["std-env@3.9.0", "", {}, "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw=="], + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], - "streamx": ["streamx@2.22.1", "", { "dependencies": { "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" } }, "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA=="], + "streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="], "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], - "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="], - "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], - - "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - - "strip-literal": ["strip-literal@3.0.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA=="], + "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], "stripe": ["stripe@18.0.0", "", { "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" } }, "sha512-3Fs33IzKUby//9kCkCa1uRpinAoTvj6rJgQ2jrBEysoxEvfsclvXdna1amyEYbA2EKkjynuB4+L/kleCCaWTpA=="], "strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], - "style-to-js": ["style-to-js@1.1.17", "", { "dependencies": { "style-to-object": "1.0.9" } }, "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA=="], + "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], + + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], - "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="], + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], - "supports-color": ["supports-color@10.0.0", "", {}, "sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ=="], + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], + + "superstruct": ["superstruct@1.0.4", "", {}, "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], "system-architecture": ["system-architecture@0.1.0", "", {}, "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA=="], - "tar": ["tar@6.2.1", "", { "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" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + "tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="], - "tar-fs": ["tar-fs@3.1.0", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w=="], + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], + + "tar": ["tar@7.5.2", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg=="], "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], "terracotta": ["terracotta@1.0.6", "", { "dependencies": { "solid-use": "^0.9.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-yVrmT/Lg6a3tEbeYEJH8ksb1PYkR5FA9k5gr1TchaSNIiA2ZWs5a+koEbePXwlBP0poaV7xViZ/v50bQFcMgqw=="], - "terser": ["terser@5.43.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg=="], + "terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="], "text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="], - "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + + "three": ["three@0.177.0", "", {}, "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg=="], + + "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="], "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], - "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], - "tmp": ["tmp@0.2.4", "", {}, "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], + "tinyrainbow": ["tinyrainbow@3.0.3", "", {}, "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q=="], - "to-buffer": ["to-buffer@1.2.1", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ=="], + "titleize": ["titleize@4.0.0", "", {}, "sha512-ZgUJ1K83rhdu7uh7EHAC2BgY5DzoX8V5rTvoWI4vFysggi6YjLe5gUXABPWAU7VkvGP7P/0YiWq+dcPeYDsf1g=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -2803,81 +3720,91 @@ "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - "toml": ["toml@3.0.0", "", {}, "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="], + "token-types": ["token-types@4.2.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="], - "toolbeam-docs-theme": ["toolbeam-docs-theme@0.4.5", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-8yu1Q57pYujy1EnQuZ5JzrV6uzTWwUAcTkBkkujtFNNUBC8jTASWp5WypiViVMd59oFqzedy1PR0G9nBBhZvRQ=="], + "toolbeam-docs-theme": ["toolbeam-docs-theme@0.4.8", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-b+5ynEFp4Woe5a22hzNQm42lD23t13ZMihVxHbzjA50zdcM9aOSJTIjdJ0PDSd4/50HbBXcpHiQsz6rM4N88ww=="], "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "tree-sitter": ["tree-sitter@0.22.4", "", { "dependencies": { "node-addon-api": "^8.3.0", "node-gyp-build": "^4.8.4" } }, "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg=="], - - "tree-sitter-bash": ["tree-sitter-bash@0.23.3", "", { "dependencies": { "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.21.1" }, "optionalPeers": ["tree-sitter"] }, "sha512-36cg/GQ2YmIbeiBeqeuh4fBJ6i4kgVouDaqTxqih5ysPag+zHufyIaxMOFeM8CeplwAK/Luj1o5XHqgdAfoCZg=="], + "traverse": ["traverse@0.3.9", "", {}, "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ=="], - "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], + "tree-sitter-bash": ["tree-sitter-bash@0.25.0", "", { "dependencies": { "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.25.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-gZtlj9+qFS81qKxpLfD6H0UssQ3QBc/F0nKkPsiFDyfQF2YBqYvglFJUzchrPpVhZe9kLZTrJ9n2J6lmka69Vg=="], "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], - "triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="], - "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], + "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], + + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], "tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tuf-js": ["tuf-js@2.2.1", "", { "dependencies": { "@tufjs/models": "2.0.1", "debug": "^4.3.4", "make-fetch-happen": "^13.0.1" } }, "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA=="], + "tsscmp": ["tsscmp@1.0.6", "", {}, "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="], + + "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], + + "turbo": ["turbo@2.5.6", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.6", "turbo-darwin-arm64": "2.5.6", "turbo-linux-64": "2.5.6", "turbo-linux-arm64": "2.5.6", "turbo-windows-64": "2.5.6", "turbo-windows-arm64": "2.5.6" }, "bin": { "turbo": "bin/turbo" } }, "sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w=="], + + "turbo-darwin-64": ["turbo-darwin-64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A=="], + + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA=="], - "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + "turbo-linux-64": ["turbo-linux-64@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA=="], + + "turbo-linux-arm64": ["turbo-linux-arm64@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ=="], + + "turbo-windows-64": ["turbo-windows-64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg=="], + + "turbo-windows-arm64": ["turbo-windows-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q=="], "turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="], + "tw-to-css": ["tw-to-css@0.0.12", "", { "dependencies": { "postcss": "8.4.31", "postcss-css-variables": "0.18.0", "tailwindcss": "3.3.2" } }, "sha512-rQAsQvOtV1lBkyCw+iypMygNHrShYAItES5r8fMsrhhaj5qrV2LkZyXc8ccEH+u5bFjHjQ9iuxe90I7Kykf6pw=="], + "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], - "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], - "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], - - "ulid": ["ulid@3.0.0", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-yvZYdXInnJve6LdlPIuYmURdS2NP41ZoF4QW7SXwbUKYt53+0eDAySO+rGSvM2O/ciuB/G+8N7GQrZ1mCJpuqw=="], + "ulid": ["ulid@3.0.1", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="], "ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="], - "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "unctx": ["unctx@2.4.1", "", { "dependencies": { "acorn": "^8.14.0", "estree-walker": "^3.0.3", "magic-string": "^0.30.17", "unplugin": "^2.1.0" } }, "sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg=="], + "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], - "undici": ["undici@7.13.0", "", {}, "sha512-l+zSMssRqrzDcb3fjMkjjLGmuiiK2pMIcV++mJaAc9vhjSGpvM7h43QgP+OAMb1GImHmbPyG2tBXeuyG5iY4gA=="], + "undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="], "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "unenv": ["unenv@1.10.0", "", { "dependencies": { "consola": "^3.2.3", "defu": "^6.1.4", "mime": "^3.0.0", "node-fetch-native": "^1.6.4", "pathe": "^1.1.2" } }, "sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ=="], + "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], "unicode-properties": ["unicode-properties@1.4.1", "", { "dependencies": { "base64-js": "^1.3.0", "unicode-trie": "^2.0.0" } }, "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg=="], "unicode-trie": ["unicode-trie@2.0.0", "", { "dependencies": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" } }, "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ=="], - "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], - "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], "unifont": ["unifont@0.5.2", "", { "dependencies": { "css-tree": "^3.0.0", "ofetch": "^1.4.1", "ohash": "^2.0.0" } }, "sha512-LzR4WUqzH9ILFvjLAUU7dK3Lnou/qd5kD+IakBtBK4S15/+x2y9VX+DcWQv6s551R6W+vzwgVS6tFg3XggGBgg=="], - "unimport": ["unimport@5.2.0", "", { "dependencies": { "acorn": "^8.15.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.1", "magic-string": "^0.30.17", "mlly": "^1.7.4", "pathe": "^2.0.3", "picomatch": "^4.0.3", "pkg-types": "^2.2.0", "scule": "^1.3.0", "strip-literal": "^3.0.0", "tinyglobby": "^0.2.14", "unplugin": "^2.3.5", "unplugin-utils": "^0.2.4" } }, "sha512-bTuAMMOOqIAyjV4i4UH7P07pO+EsVxmhOzQ2YJ290J6mkLUdozNhb5I/YoOEheeNADC03ent3Qj07X0fWfUpmw=="], - - "unique-filename": ["unique-filename@3.0.0", "", { "dependencies": { "unique-slug": "^4.0.0" } }, "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g=="], - - "unique-slug": ["unique-slug@4.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ=="], - "unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="], - "unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="], + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], "unist-util-modify-children": ["unist-util-modify-children@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" } }, "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw=="], @@ -2893,51 +3820,37 @@ "unist-util-visit-children": ["unist-util-visit-children@3.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA=="], - "unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="], + "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], "universal-github-app-jwt": ["universal-github-app-jwt@2.2.2", "", {}, "sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw=="], "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], - "unixify": ["unixify@1.0.0", "", { "dependencies": { "normalize-path": "^2.1.1" } }, "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg=="], + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - "unplugin": ["unplugin@2.3.5", "", { "dependencies": { "acorn": "^8.14.1", "picomatch": "^4.0.2", "webpack-virtual-modules": "^0.6.2" } }, "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw=="], - - "unplugin-utils": ["unplugin-utils@0.2.5", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg=="], - - "unstorage": ["unstorage@1.16.1", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.3", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.6", "ofetch": "^1.4.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ=="], + "unstorage": ["unstorage@2.0.0-alpha.4", "", { "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "chokidar": "^4.0.3", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "lru-cache": "^11.2.2", "mongodb": "^6.20.0", "ofetch": "*", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "chokidar", "db0", "idb-keyval", "ioredis", "lru-cache", "mongodb", "ofetch", "uploadthing"] }, "sha512-ywXZMZRfrvmO1giJeMTCw6VUn0ALYxVl8pFqJPStiyQUvgJImejtAHrKvXPj4QGJAoS/iLGcVGF6ljN/lkh1bw=="], - "untun": ["untun@0.1.3", "", { "dependencies": { "citty": "^0.1.5", "consola": "^3.2.3", "pathe": "^1.1.1" }, "bin": { "untun": "bin/untun.mjs" } }, "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ=="], + "unzip-stream": ["unzip-stream@0.3.4", "", { "dependencies": { "binary": "^0.3.0", "mkdirp": "^0.5.1" } }, "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw=="], - "untyped": ["untyped@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "defu": "^6.1.4", "jiti": "^2.4.2", "knitwork": "^1.2.0", "scule": "^1.3.0" }, "bin": { "untyped": "dist/cli.mjs" } }, "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g=="], + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], - "unwasm": ["unwasm@0.3.9", "", { "dependencies": { "knitwork": "^1.0.0", "magic-string": "^0.30.8", "mlly": "^1.6.1", "pathe": "^1.1.2", "pkg-types": "^1.0.3", "unplugin": "^1.10.0" } }, "sha512-LDxTx/2DkFURUd+BU1vUsF/moj0JsoTvl+2tcg2AUOiEzVturhGGx17/IMgGvKUYdZwr33EJHtChCJuhu9Ouvg=="], - - "upath": ["upath@1.2.0", "", {}, "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="], - - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], - - "uqr": ["uqr@0.1.2", "", {}, "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA=="], + "url": ["url@0.10.3", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="], - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], - "url": ["url@0.10.3", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="], + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], - "urlpattern-polyfill": ["urlpattern-polyfill@8.0.2", "", {}, "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ=="], + "utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="], "util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - "uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], - - "validate-html-nesting": ["validate-html-nesting@1.2.3", "", {}, "sha512-kdkWdCl6eCeLlRShJKbjVOU2kFKxMF8Ghu50n+crEoyx+VKm3FxAxF9z4DCy6+bbTOqNW0+jcIYRnjoIRzigRw=="], - - "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], + "uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], @@ -2947,69 +3860,75 @@ "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "vinxi": ["vinxi@0.5.8", "", { "dependencies": { "@babel/core": "^7.22.11", "@babel/plugin-syntax-jsx": "^7.22.5", "@babel/plugin-syntax-typescript": "^7.22.5", "@types/micromatch": "^4.0.2", "@vinxi/listhen": "^1.5.6", "boxen": "^8.0.1", "chokidar": "^4.0.3", "citty": "^0.1.6", "consola": "^3.4.2", "crossws": "^0.3.4", "dax-sh": "^0.43.0", "defu": "^6.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.3", "get-port-please": "^3.1.2", "h3": "1.15.3", "hookable": "^5.5.3", "http-proxy": "^1.18.1", "micromatch": "^4.0.8", "nitropack": "^2.11.10", "node-fetch-native": "^1.6.6", "path-to-regexp": "^6.2.1", "pathe": "^1.1.1", "radix3": "^1.1.2", "resolve": "^1.22.10", "serve-placeholder": "^2.0.1", "serve-static": "^1.15.0", "tinyglobby": "^0.2.14", "ufo": "^1.6.1", "unctx": "^2.4.1", "unenv": "^1.10.0", "unstorage": "^1.16.0", "vite": "^6.3.3", "zod": "^3.24.3" }, "bin": { "vinxi": "bin/cli.mjs" } }, "sha512-1pGA+cU1G9feBQ1sd5FMftPuLUT8NSX880AvELhNWqoqWhe2jeSOQxjDPxlA3f1AC+Bbknl4UPKHyVXmfLZQjw=="], + "virtua": ["virtua@0.42.3", "", { "peerDependencies": { "react": ">=16.14.0", "react-dom": ">=16.14.0", "solid-js": ">=1.0", "svelte": ">=5.0", "vue": ">=3.2" }, "optionalPeers": ["react", "react-dom", "solid-js", "svelte", "vue"] }, "sha512-5FoAKcEvh05qsUF97Yz42SWJ7bwnPExjUYHGuoxz1EUtfWtaOgXaRwnylJbDpA0QcH1rKvJ2qsGRi9MK1fpQbg=="], + + "vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="], - "vite": ["vite@6.2.2", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ=="], + "vite-plugin-dynamic-import": ["vite-plugin-dynamic-import@1.6.0", "", { "dependencies": { "acorn": "^8.12.1", "es-module-lexer": "^1.5.4", "fast-glob": "^3.3.2", "magic-string": "^0.30.11" } }, "sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg=="], - "vite-plugin-pages": ["vite-plugin-pages@0.32.5", "", { "dependencies": { "@types/debug": "^4.1.12", "debug": "^4.4.0", "dequal": "^2.0.3", "extract-comments": "^1.1.0", "fast-glob": "^3.3.3", "json5": "^2.2.3", "local-pkg": "^1.0.0", "picocolors": "^1.1.1", "yaml": "^2.7.0" }, "peerDependencies": { "@vue/compiler-sfc": "^2.7.0 || ^3.0.0", "vite": "^2.0.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["@vue/compiler-sfc"] }, "sha512-GY2JAt+4vZ4BqTtw+4CSUxPgYiqamrMRIzYk2AtJvQHeBoMlctsQW+tgCpKriUKINiKfi6NegbP07r1XrdxTWA=="], + "vite-plugin-icons-spritesheet": ["vite-plugin-icons-spritesheet@3.0.1", "", { "dependencies": { "chalk": "^5.4.1", "glob": "^11.0.1", "node-html-parser": "^7.0.1", "tinyexec": "^0.3.2" }, "peerDependencies": { "vite": ">=5.2.0" } }, "sha512-Cr0+Z6wRMwSwKisWW9PHeTjqmQFv0jwRQQMc3YgAhAgZEe03j21el0P/CA31KN/L5eiL1LhR14VTXl96LetonA=="], - "vite-plugin-solid": ["vite-plugin-solid@2.11.6", "", { "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" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-Sl5CTqJTGyEeOsmdH6BOgalIZlwH3t4/y0RQuFLMGnvWMBvxb4+lq7x3BSiAw6etf0QexfNJW7HSOO/Qf7pigg=="], + "vite-plugin-solid": ["vite-plugin-solid@2.11.10", "", { "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" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw=="], "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], + "vitest": ["vitest@4.0.16", "", { "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", "@vitest/pretty-format": "4.0.16", "@vitest/runner": "4.0.16", "@vitest/snapshot": "4.0.16", "@vitest/spy": "4.0.16", "@vitest/utils": "4.0.16", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.16", "@vitest/browser-preview": "4.0.16", "@vitest/browser-webdriverio": "4.0.16", "@vitest/ui": "4.0.16", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q=="], + "vscode-jsonrpc": ["vscode-jsonrpc@8.2.1", "", {}, "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ=="], "vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], - "walk-up-path": ["walk-up-path@3.0.1", "", {}, "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA=="], - "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], - "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], - "web-tree-sitter": ["web-tree-sitter@0.22.6", "", {}, "sha512-hS87TH71Zd6mGAmYCvlgxeGDjqd9GTeqXNqTT+u0Gs51uIozNIaaq/kUAbV/Zf56jb2ZOyG8BxZs2GG9wbLi6Q=="], + "web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], - "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], + "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], "which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="], "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], - "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], - - "winston": ["winston@3.17.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw=="], - - "winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="], + "why-is-node-running": ["why-is-node-running@3.2.2", "", { "bin": { "why-is-node-running": "cli.js" } }, "sha512-NKUzAelcoCXhXL4dJzKIwXeR8iEVqsA0Lq6Vnd0UXvgaKbzVo4ZTHROF2Jidrv+SgxOQ03fMinnNhzZATxOD3A=="], - "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], - "workerd": ["workerd@1.20250730.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250730.0", "@cloudflare/workerd-darwin-arm64": "1.20250730.0", "@cloudflare/workerd-linux-64": "1.20250730.0", "@cloudflare/workerd-linux-arm64": "1.20250730.0", "@cloudflare/workerd-windows-64": "1.20250730.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-w6e0WM2YGfYQGmg0dewZeLUYIxAzMYK1R31vaS4HHHjgT32Xqj0eVQH+leegzY51RZPNCvw5pe8DFmW4MGf8Fg=="], + "workerd": ["workerd@1.20251118.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251118.0", "@cloudflare/workerd-darwin-arm64": "1.20251118.0", "@cloudflare/workerd-linux-64": "1.20251118.0", "@cloudflare/workerd-linux-arm64": "1.20251118.0", "@cloudflare/workerd-windows-64": "1.20251118.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Om5ns0Lyx/LKtYI04IV0bjIrkBgoFNg0p6urzr2asekJlfP18RqFzyqMFZKf0i9Gnjtz/JfAS/Ol6tjCe5JJsQ=="], - "wrangler": ["wrangler@4.27.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.5.0", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250730.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.19", "workerd": "1.20250730.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250730.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-YNHZyMNWebFt9jD6dc20tQrCmnSzJj3SoB0FFa90w11Cx4lbP3d+rUZYjb18Zt+OGSMay1wT2PzwT2vCTskkmg=="], + "wrangler": ["wrangler@4.50.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.11", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251118.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251118.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251118.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-+nuZuHZxDdKmAyXOSrHlciGshCoAPiy5dM+t6mEohWm7HpXvTHmWQGUf/na9jjWlWJHCJYOWzkA1P5HBJqrIEA=="], - "wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="], + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + "wsl-utils": ["wsl-utils@0.3.0", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-3sFIGLiaDP7rTO4xh3g+b3AzhYDIUGGywE/WsmqzJWDxus5aJXVnPTNC/6L+r2WzrwXqVOdD262OaO+cEyPMSQ=="], + "xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], + "xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="], + "xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], - "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + "xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="], "xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="], @@ -3023,23 +3942,21 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], - - "yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="], + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], "yocto-spinner": ["yocto-spinner@0.2.3", "", { "dependencies": { "yoctocolors": "^2.1.1" } }, "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ=="], - "yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="], + "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], + + "yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="], - "youch": ["youch@4.1.0-beta.8", "", { "dependencies": { "@poppinss/colors": "^4.1.4", "@poppinss/dumper": "^0.6.3", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.1" } }, "sha512-rY2A2lSF7zC+l7HH9Mq+83D1dLlsPnEvy8jTouzaptDZM6geqZ3aJe/b7ULCwRURPtWV3vbDjA2DDMdoBol0HQ=="], + "youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], "zip-stream": ["zip-stream@6.0.1", "", { "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", "readable-stream": "^4.0.0" } }, "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "zod-openapi": ["zod-openapi@4.1.0", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-bRCwRYhEO9CmFLyKgJX8h6j1dRtRiwOe+TLzMVPyV0pRW5vRIgb1rLgIGcuRZ5z3MmSVrZqbv3yva4IJrtZK4g=="], + "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], "zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="], @@ -3047,81 +3964,103 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@ai-sdk/amazon-bedrock/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], + "@actions/artifact/@actions/core": ["@actions/core@2.0.1", "", { "dependencies": { "@actions/exec": "^2.0.0", "@actions/http-client": "^3.0.0" } }, "sha512-oBfqT3GwkvLlo1fjvhQLQxuwZCGTarTE5OuZ2Wg10hvhBj7LRIlF611WT4aZS6fDhO5ZKlY7lCAZTlpmyaHaeg=="], - "@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], + "@actions/core/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], - "@ai-sdk/amazon-bedrock/aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + "@actions/github/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], - "@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.1", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-/iP1sKc6UdJgGH98OCly7sWJKv+J9G47PnTjIj40IJMUQKwDrUMyf7zOOfRtPwSuNifYhSoJQ4s1WltI65gJ/g=="], + "@actions/github/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@9.2.2", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ=="], - "@astrojs/cloudflare/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], + "@actions/github/@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@10.4.1", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg=="], - "@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], + "@actions/github/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], - "@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.3", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.1.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.2.1", "smol-toml": "^1.3.4", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-DDRtD1sPvAuA7ms2btc9A7/7DApKqgLMNrE6kh5tmkfy8utD0Z738gqd3p5aViYYdUtHIyEJ1X4mCMxfCfu15w=="], + "@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], - "@astrojs/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.57", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-DREpYqW2pylgaj69gZ+K8u92bo9DaMgFdictYnY+IwYeY3bawQ4zI7l/o1VkDsBDljAx8iYz5lPURwVZNu+Xpg=="], - "@astrojs/sitemap/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="], + "@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.5", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA=="], - "@astrojs/solid-js/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], + "@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="], - "@astrojs/solid-js/vite-plugin-solid": ["vite-plugin-solid@2.11.8", "", { "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" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg=="], + "@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="], - "@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.840.0", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA=="], + "@ai-sdk/azure/@ai-sdk/openai": ["@ai-sdk/openai@2.0.89", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4+qWkBCbL9HPKbgrUO/F2uXZ8GqrYxHa8SWEYIzxEJ9zvWw3ISr3t1/27O1i8MGSym+PzEyHBT48EV4LAwWaEw=="], - "@aws-crypto/sha256-browser/@aws-sdk/types": ["@aws-sdk/types@3.840.0", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA=="], + "@ai-sdk/cerebras/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-thubwhRtv9uicAxSWwNpinM7hiL/0CkhL/ymPaHuKvI494J7HIzn8KQZQ2ymRz284WTIZnI7VMyyejxW4RMM6w=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@ai-sdk/deepinfra/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-thubwhRtv9uicAxSWwNpinM7hiL/0CkhL/ymPaHuKvI494J7HIzn8KQZQ2ymRz284WTIZnI7VMyyejxW4RMM6w=="], - "@aws-crypto/sha256-js/@aws-sdk/types": ["@aws-sdk/types@3.840.0", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA=="], + "@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.57", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-DREpYqW2pylgaj69gZ+K8u92bo9DaMgFdictYnY+IwYeY3bawQ4zI7l/o1VkDsBDljAx8iYz5lPURwVZNu+Xpg=="], - "@aws-crypto/util/@aws-sdk/types": ["@aws-sdk/types@3.840.0", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA=="], + "@ai-sdk/openai/@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="], - "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="], + + "@ai-sdk/openai-compatible/@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="], + + "@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="], - "@aws-sdk/client-sso/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@ai-sdk/togetherai/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-thubwhRtv9uicAxSWwNpinM7hiL/0CkhL/ymPaHuKvI494J7HIzn8KQZQ2ymRz284WTIZnI7VMyyejxW4RMM6w=="], - "@aws-sdk/core/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@ai-sdk/vercel/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-thubwhRtv9uicAxSWwNpinM7hiL/0CkhL/ymPaHuKvI494J7HIzn8KQZQ2ymRz284WTIZnI7VMyyejxW4RMM6w=="], - "@aws-sdk/credential-provider-env/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@ai-sdk/xai/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-thubwhRtv9uicAxSWwNpinM7hiL/0CkhL/ymPaHuKvI494J7HIzn8KQZQ2ymRz284WTIZnI7VMyyejxW4RMM6w=="], - "@aws-sdk/credential-provider-http/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@astrojs/cloudflare/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], - "@aws-sdk/credential-provider-ini/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], + + "@astrojs/markdown-remark/shiki": ["shiki@3.15.0", "", { "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" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="], + + "@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.9", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.5", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.13.0", "smol-toml": "^1.4.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hX2cLC/KW74Io1zIbn92kI482j9J7LleBLGCVU9EP3BeH5MVrnFawOnqD0t/q6D1Z+ZNeQG2gNKMslCcO36wng=="], + + "@astrojs/sitemap/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@astrojs/solid-js/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + + "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + + "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-sdk/credential-provider-node/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-crypto/sha256-js/@aws-sdk/types": ["@aws-sdk/types@3.775.0", "", { "dependencies": { "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA=="], - "@aws-sdk/credential-provider-process/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + + "@aws-sdk/client-sts/@aws-sdk/core": ["@aws-sdk/core@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/core": "^3.2.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/signature-v4": "^5.0.2", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.782.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.775.0", "@aws-sdk/credential-provider-http": "3.775.0", "@aws-sdk/credential-provider-ini": "3.782.0", "@aws-sdk/credential-provider-process": "3.775.0", "@aws-sdk/credential-provider-sso": "3.782.0", "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/credential-provider-imds": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw=="], + + "@aws-sdk/client-sts/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w=="], - "@aws-sdk/credential-provider-sso/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw=="], - "@aws-sdk/credential-provider-web-identity/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA=="], - "@aws-sdk/middleware-host-header/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.782.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@smithy/core": "^3.2.0", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg=="], - "@aws-sdk/middleware-logger/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/types": "^4.2.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.2", "tslib": "^2.6.2" } }, "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ=="], - "@aws-sdk/middleware-recursion-detection/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/types": ["@aws-sdk/types@3.775.0", "", { "dependencies": { "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA=="], - "@aws-sdk/middleware-user-agent/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.782.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/types": "^4.2.0", "@smithy/util-endpoints": "^3.0.2", "tslib": "^2.6.2" } }, "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw=="], - "@aws-sdk/nested-clients/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/types": "^4.2.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A=="], - "@aws-sdk/region-config-resolver/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/client-sts/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.782.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA=="], - "@aws-sdk/token-providers/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - "@aws-sdk/types/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@azure/core-http/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="], - "@aws-sdk/util-endpoints/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@azure/core-http/@azure/core-tracing": ["@azure/core-tracing@1.0.0-preview.13", "", { "dependencies": { "@opentelemetry/api": "^1.0.1", "tslib": "^2.2.0" } }, "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ=="], - "@aws-sdk/util-user-agent-browser/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@azure/core-http/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], - "@aws-sdk/util-user-agent-node/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@azure/core-http/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], - "@babel/core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@azure/core-xml/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -3129,338 +4068,354 @@ "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/helper-create-class-features-plugin/@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], - "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/helper-member-expression-to-functions/@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], + "@bufbuild/protoplugin/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="], - "@babel/helper-replace-supers/@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], + "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], - "@babel/template/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], - "@cloudflare/kv-asset-handler/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + "@expressive-code/plugin-shiki/shiki": ["shiki@3.15.0", "", { "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" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="], - "@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="], + "@gitlab/gitlab-ai-provider/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@hey-api/json-schema-ref-parser/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], - "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + "@hey-api/openapi-ts/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="], - "@grpc/proto-loader/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "@hono/zod-validator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@mapbox/node-pre-gyp/nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], + "@jimp/plugin-blit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@mapbox/node-pre-gyp/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], + "@jimp/plugin-circle/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "@jimp/plugin-color/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@modelcontextprotocol/sdk/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="], + "@jimp/plugin-contain/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/dev-utils/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="], + "@jimp/plugin-cover/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/dev-utils/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + "@jimp/plugin-crop/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/dev-utils/write-file-atomic": ["write-file-atomic@6.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ=="], + "@jimp/plugin-displace/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/functions/is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], + "@jimp/plugin-fisheye/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/@babel/types": ["@babel/types@7.28.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg=="], + "@jimp/plugin-flip/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/@netlify/serverless-functions-api": ["@netlify/serverless-functions-api@2.2.0", "", {}, "sha512-eQNnGUMyatgEeFJ8iKI2DT7wXDEjbWmZ+hJpCZtfg1bVsD4JdprIhLqdrUqmrDgPG2r45sQYigO9oq8BWXO37w=="], + "@jimp/plugin-mask/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="], + "@jimp/plugin-print/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], + "@jimp/plugin-quantize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="], + "@jimp/plugin-resize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@jimp/plugin-rotate/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/p-map": ["p-map@7.0.3", "", {}, "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA=="], + "@jimp/plugin-threshold/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], + "@jimp/types/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@netlify/zip-it-and-ship-it/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "@jsx-email/cli/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "@jsx-email/cli/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], - "@npmcli/arborist/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "@jsx-email/cli/tailwindcss": ["tailwindcss@3.3.3", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w=="], - "@npmcli/arborist/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@jsx-email/cli/vite": ["vite@4.5.14", "", { "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", "rollup": "^3.27.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g=="], - "@npmcli/git/ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="], + "@jsx-email/doiuse-email/htmlparser2": ["htmlparser2@9.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", "entities": "^4.5.0" } }, "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ=="], - "@npmcli/git/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], - "@npmcli/map-workspaces/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@modelcontextprotocol/sdk/jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], - "@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="], + "@modelcontextprotocol/sdk/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], - "@openauthjs/openauth/aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], - "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@octokit/auth-app/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], - "@openauthjs/solid/@openauthjs/openauth": ["@openauthjs/openauth@0.4.2", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-8+Bia559iffrZXfQ0LWXrVVVriochS88pDtB8indyQ1S+40MQgDBu8aBzKt+fgSrTmoQGCTT+wlOXgbjc9qIcw=="], + "@octokit/auth-app/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@opencode/cloud-web/solid-js": ["solid-js@1.9.5", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "^1.1.0", "seroval-plugins": "^1.1.0" } }, "sha512-ogI3DaFcyn6UhYhrgcyRAMbu/buBJitYQASZz5WzfQVPP10RD2AbCoRZ517psnezrasyCbWzIxZ6kVqet768xw=="], + "@octokit/auth-oauth-app/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], - "@opentelemetry/instrumentation-grpc/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.27.0", "", {}, "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg=="], + "@octokit/auth-oauth-app/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="], + "@octokit/auth-oauth-device/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], - "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], + "@octokit/auth-oauth-device/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@parcel/watcher/node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + "@octokit/auth-oauth-user/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], - "@parcel/watcher-wasm/napi-wasm": ["napi-wasm@1.1.3", "", { "bundled": true }, "sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg=="], + "@octokit/auth-oauth-user/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@poppinss/dumper/@sindresorhus/is": ["@sindresorhus/is@7.0.2", "", {}, "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw=="], + "@octokit/core/@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="], - "@pulumi/pulumi/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + "@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], - "@pulumi/pulumi/picomatch": ["picomatch@3.0.1", "", {}, "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag=="], + "@octokit/core/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], - "@rollup/plugin-commonjs/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@octokit/endpoint/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], - "@rollup/plugin-inject/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@octokit/endpoint/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], - "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@octokit/graphql/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], + + "@octokit/graphql/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + + "@octokit/oauth-methods/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], + + "@octokit/oauth-methods/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@smithy/abort-controller/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/oauth-methods/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@smithy/config-resolver/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/plugin-paginate-rest/@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="], - "@smithy/core/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], - "@smithy/core/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="], - "@smithy/credential-provider-imds/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], - "@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/plugin-retry/@octokit/types": ["@octokit/types@6.41.0", "", { "dependencies": { "@octokit/openapi-types": "^12.11.0" } }, "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg=="], - "@smithy/hash-node/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/request/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], - "@smithy/invalid-dependency/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/request/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], - "@smithy/middleware-content-length/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], - "@smithy/middleware-endpoint/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/rest/@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="], - "@smithy/middleware-retry/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@octokit/rest/@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], - "@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="], + + "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + + "@opencode-ai/desktop/@actions/artifact": ["@actions/artifact@4.0.0", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="], - "@smithy/middleware-serde/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], - "@smithy/middleware-stack/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], - "@smithy/node-config-provider/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], - "@smithy/node-http-handler/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.9", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.1" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.8" }, "optionalPeers": ["solid-js"] }, "sha512-pCnxWrciluXCeli/dj5PIEHgbNzim3evtTn12snjqqg8QZWJNMjH1AWIp4iG/tbVjqQ72aBEymMSagvmgxubXw=="], - "@smithy/property-provider/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="], + + "@pierre/diffs/@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="], - "@smithy/protocol-http/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@pierre/diffs/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-ZfWJNm2VMhKkQIKT9qXbs76RRcT0SF/CAvEz0+RkpUDAoDaCx0uFdCGzSRiD9gSlhm6AHkjdieOBJMaO2eC1rQ=="], - "@smithy/querystring-builder/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@pierre/diffs/@shikijs/transformers": ["@shikijs/transformers@3.19.0", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/types": "3.19.0" } }, "sha512-e6vwrsyw+wx4OkcrDbL+FVCxwx8jgKiCoXzakVur++mIWVcgpzIi8vxf4/b4dVTYrV/nUx5RjinMf4tq8YV8Fw=="], - "@smithy/querystring-parser/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@pierre/diffs/shiki": ["shiki@3.19.0", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/engine-javascript": "3.19.0", "@shikijs/engine-oniguruma": "3.19.0", "@shikijs/langs": "3.19.0", "@shikijs/themes": "3.19.0", "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-77VJr3OR/VUZzPiStyRhADmO2jApMM0V2b1qf0RpfWya8Zr1PeZev5AEpPGAAKWdiYUtcZGBE4F5QvJml1PvWA=="], - "@smithy/service-error-classification/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], - "@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@protobuf-ts/plugin/typescript": ["typescript@3.9.10", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q=="], - "@smithy/signature-v4/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - "@smithy/smithy-client/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@shikijs/engine-javascript/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], - "@smithy/url-parser/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@shikijs/engine-oniguruma/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], - "@smithy/util-defaults-mode-browser/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@shikijs/langs/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], - "@smithy/util-defaults-mode-node/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@shikijs/themes/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], - "@smithy/util-endpoints/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@slack/bolt/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], - "@smithy/util-middleware/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@slack/oauth/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], - "@smithy/util-retry/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@slack/socket-mode/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], - "@smithy/util-stream/@smithy/types": ["@smithy/types@4.3.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw=="], + "@slack/socket-mode/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], - "@solidjs/start/shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="], + "@slack/web-api/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], - "@solidjs/start/vite-plugin-solid": ["vite-plugin-solid@2.11.8", "", { "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" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg=="], + "@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="], - "@tufjs/models/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="], - "@types/bun/bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], + "@slack/web-api/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="], - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@smithy/eventstream-codec/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@vercel/nft/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.5", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA=="], - "@vinxi/listhen/h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="], + "@solidjs/start/esbuild": ["esbuild@0.25.12", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], - "@vinxi/listhen/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + "@solidjs/start/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], - "@vinxi/plugin-directives/magicast": ["magicast@0.2.11", "", { "dependencies": { "@babel/parser": "^7.22.16", "@babel/types": "^7.22.17", "recast": "^0.23.4" } }, "sha512-6saXbRDA1HMkqbsvHOU6HBjCVgZT460qheRkLhJQHWAbhXoWESI3Kn/dGGXyKs15FFKR85jsUqFx2sMK0wy/5g=="], + "@solidjs/start/shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="], + + "@solidjs/start/vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="], + + "@tailwindcss/oxide/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], - "@vinxi/server-components/magicast": ["magicast@0.2.11", "", { "dependencies": { "@babel/parser": "^7.22.16", "@babel/types": "^7.22.17", "recast": "^0.23.4" } }, "sha512-6saXbRDA1HMkqbsvHOU6HBjCVgZT460qheRkLhJQHWAbhXoWESI3Kn/dGGXyKs15FFKR85jsUqFx2sMK0wy/5g=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], - "@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], - "@whatwg-node/fetch/urlpattern-polyfill": ["urlpattern-polyfill@10.1.0", "", {}, "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw=="], + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], - "ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.1", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-/iP1sKc6UdJgGH98OCly7sWJKv+J9G47PnTjIj40IJMUQKwDrUMyf7zOOfRtPwSuNifYhSoJQ4s1WltI65gJ/g=="], + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "archiver/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "archiver-utils/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "archiver-utils/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "archiver-utils/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], "astro/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], "astro/diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="], - "astro/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], - - "astro/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], + "astro/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "astro/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="], - - "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], + "astro/shiki": ["shiki@3.15.0", "", { "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" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="], - "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "astro/unstorage": ["unstorage@1.17.3", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q=="], - "cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "astro/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], - "cacheable-request/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], + "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "clipboardy/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], + "aws-sdk/events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="], - "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], + "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], - "colorspace/color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="], + "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], - "compress-commons/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "crc32-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "body-parser/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - "dax-sh/undici-types": ["undici-types@5.28.4", "", {}, "sha512-3OeMF5Lyowe8VW0skf5qaIE7Or3yS9LS7fvMUI0gg4YxpIBVg0L8BxCmROw2CcYhSkpR68Epz7CGc8MPj94Uww=="], + "bun-webgpu/@webgpu/types": ["@webgpu/types@0.1.66", "", {}, "sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA=="], - "drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], + "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], - "estree-util-to-js/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], - "express/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], + "condense-newlines/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], - "express/serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "extract-zip/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], + "dot-prop/type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="], - "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], - "giget/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "editorconfig/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], - "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "editorconfig/minimatch": ["minimatch@9.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w=="], - "globby/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + "editorconfig/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "gray-matter/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + "engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], - "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], + "es-get-iterator/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "esbuild-plugin-copy/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + "esbuild-plugin-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - "ignore-walk/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], - "ip-address/sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + "express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], - "lambda-local/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], + "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + "express/path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], - "listhen/@parcel/watcher-wasm": ["@parcel/watcher-wasm@2.5.1", "", { "dependencies": { "is-glob": "^4.0.3", "micromatch": "^4.0.5", "napi-wasm": "^1.1.0" } }, "sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw=="], + "express/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - "listhen/h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="], + "fetch-blob/web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], - "local-pkg/pkg-types": ["pkg-types@2.2.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ=="], + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "make-fetch-happen/negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], + "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "merge-options/is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="], + "gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "gel/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], + "glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], - "miniflare/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], + "globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "miniflare/youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], + "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], - "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], + "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], - "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "html-minifier-terser/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], - "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "js-beautify/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "jsonwebtoken/jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="], - "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "jsonwebtoken/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], - "netlify/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - "nitropack/c12": ["c12@3.2.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-ixkEtbYafL56E6HiFuonMm1ZjoKtIo7TH68/uiEq4DAwv9NcUX2nJ95F8TrbMeNjqIkZpruo3ojXQJ+MGG5gcQ=="], + "lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "nitropack/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "md-to-react-email/marked": ["marked@7.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ=="], - "nitropack/cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], + "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - "nitropack/h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "nitropack/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], - "nitropack/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "miniflare/undici": ["undici@7.14.0", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], - "nitropack/pkg-types": ["pkg-types@2.2.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ=="], + "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], - "nitropack/serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], + "named-placeholders/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], - "nitropack/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "nitro/h3": ["h3@2.0.1-rc.5", "", { "dependencies": { "rou3": "^0.7.9", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-qkohAzCab0nLzXNm78tBjZDvtKMTmtygS8BJLT3VPczAQofdqlFXDPkXdLMJN4r05+xqneG8snZJ0HgkERCZTg=="], - "nitropack/unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="], + "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], - "node-gyp/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + "nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], - "nypm/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.57", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-DREpYqW2pylgaj69gZ+K8u92bo9DaMgFdictYnY+IwYeY3bawQ4zI7l/o1VkDsBDljAx8iYz5lPURwVZNu+Xpg=="], - "opencode/@openauthjs/openauth": ["@openauthjs/openauth@0.4.3", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw=="], + "opencode/@ai-sdk/openai": ["@ai-sdk/openai@2.0.89", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4+qWkBCbL9HPKbgrUO/F2uXZ8GqrYxHa8SWEYIzxEJ9zvWw3ISr3t1/27O1i8MGSym+PzEyHBT48EV4LAwWaEw=="], - "opencode/ulid": ["ulid@3.0.1", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="], + "opencode/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-thubwhRtv9uicAxSWwNpinM7hiL/0CkhL/ymPaHuKvI494J7HIzn8KQZQ2ymRz284WTIZnI7VMyyejxW4RMM6w=="], "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], + "opencontrol/@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], + "opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="], "opencontrol/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], @@ -3469,53 +4424,59 @@ "openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], - "p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], + "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], - "p-queue/eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "parse-bmfont-xml/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], - "parse-json/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "path-scurry/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + + "pixelmatch/pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="], - "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "pkg-up/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], - "prebuild-install/tar-fs": ["tar-fs@2.1.3", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg=="], + "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], - "precinct/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "postcss-load-config/lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], - "rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "read-pkg/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + "readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], "readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], - "rollup-plugin-visualizer/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], + "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "rollup-plugin-visualizer/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], - "rollup-plugin-visualizer/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "router/path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="], + "safe-push-apply/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], - "send/fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], - "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], - "send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + "sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "sharp/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "sitemap/@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="], + "shiki/@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="], - "sitemap/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], + "shiki/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], + + "sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], + + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "sst/aws4fetch": ["aws4fetch@1.0.18", "", {}, "sha512-3Cf+YaUl07p24MoQ46rFwulAmiyCwH2+1zw1ZyPAX5OtJ34Hh185DwB8y/qRLb6cYYYtSFJ9pthyLc0MD4e8sQ=="], "sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="], @@ -3525,97 +4486,99 @@ "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + + "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "tar/fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + "tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], - "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "tw-to-css/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], - "to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "tw-to-css/tailwindcss": ["tailwindcss@3.3.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w=="], - "tree-sitter/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], + "type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], + "unifont/ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], - "unenv/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + "utif2/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], - "unicode-trie/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="], + "vitest/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], - "unifont/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "vitest/vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="], - "unimport/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "vitest/why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], - "unimport/pkg-types": ["pkg-types@2.2.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ=="], + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "unixify/normalize-path": ["normalize-path@2.1.1", "", { "dependencies": { "remove-trailing-separator": "^1.0.1" } }, "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w=="], + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "unplugin-utils/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "unstorage/h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="], + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "unstorage/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], - "unwasm/unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="], + "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], - "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "vinxi/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], + "zod-to-ts/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], + "@actions/artifact/@actions/core/@actions/exec": ["@actions/exec@2.0.0", "", { "dependencies": { "@actions/io": "^2.0.0" } }, "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw=="], - "wrangler/unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="], + "@actions/core/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "@actions/github/@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="], - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="], - "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="], - "write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="], - "xml2js/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], + "@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA=="], - "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + "@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="], - "yauzl/buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + "@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="], - "zip-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.15.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw=="], - "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], + "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.5", "", {}, "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA=="], "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki": ["shiki@3.15.0", "", { "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" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="], - "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - "@babel/helper-create-class-features-plugin/@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - "@babel/helper-create-class-features-plugin/@babel/traverse/@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw=="], - "@babel/helper-create-class-features-plugin/@babel/traverse/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww=="], - "@babel/helper-member-expression-to-functions/@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.782.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/credential-provider-env": "3.775.0", "@aws-sdk/credential-provider-http": "3.775.0", "@aws-sdk/credential-provider-process": "3.775.0", "@aws-sdk/credential-provider-sso": "3.782.0", "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/credential-provider-imds": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw=="], - "@babel/helper-member-expression-to-functions/@babel/traverse/@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg=="], - "@babel/helper-member-expression-to-functions/@babel/traverse/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.782.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.782.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/token-providers": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ=="], - "@babel/helper-replace-supers/@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.782.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ=="], - "@babel/helper-replace-supers/@babel/traverse/@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + "@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], - "@babel/helper-replace-supers/@babel/traverse/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], + "@azure/core-http/xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], - "@cloudflare/unenv-preset/unenv/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "@azure/core-xml/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], - "@cloudflare/unenv-preset/unenv/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], @@ -3661,103 +4624,275 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@grpc/proto-loader/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/core": ["@shikijs/core@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="], - "@grpc/proto-loader/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="], + + "@expressive-code/plugin-shiki/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA=="], + + "@expressive-code/plugin-shiki/shiki/@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="], + + "@expressive-code/plugin-shiki/shiki/@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="], + + "@expressive-code/plugin-shiki/shiki/@shikijs/types": ["@shikijs/types@3.15.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "@mapbox/node-pre-gyp/nopt/abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "@jsx-email/cli/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="], + + "@jsx-email/cli/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="], + + "@jsx-email/cli/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="], + + "@jsx-email/cli/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="], + + "@jsx-email/cli/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="], + + "@jsx-email/cli/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="], + + "@jsx-email/cli/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="], + + "@jsx-email/cli/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="], + + "@jsx-email/cli/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="], + + "@jsx-email/cli/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="], + + "@jsx-email/cli/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="], + + "@jsx-email/cli/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="], + + "@jsx-email/cli/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="], + + "@jsx-email/cli/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="], + + "@jsx-email/cli/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="], + + "@jsx-email/cli/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "@jsx-email/cli/tailwindcss/glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "@jsx-email/cli/tailwindcss/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + + "@jsx-email/cli/tailwindcss/object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], + + "@jsx-email/cli/vite/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], - "@mapbox/node-pre-gyp/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "@jsx-email/cli/vite/rollup": ["rollup@3.29.5", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w=="], - "@mapbox/node-pre-gyp/tar/minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="], + "@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - "@mapbox/node-pre-gyp/tar/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], + "@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], - "@mapbox/node-pre-gyp/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "@modelcontextprotocol/sdk/express/content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], - "@netlify/dev-utils/find-up/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + "@modelcontextprotocol/sdk/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], - "@netlify/dev-utils/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "@modelcontextprotocol/sdk/express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="], + "@modelcontextprotocol/sdk/express/finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="], + "@modelcontextprotocol/sdk/express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.5", "", { "os": "android", "cpu": "arm64" }, "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg=="], + "@modelcontextprotocol/sdk/express/http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.5", "", { "os": "android", "cpu": "x64" }, "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw=="], + "@modelcontextprotocol/sdk/express/merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ=="], + "@modelcontextprotocol/sdk/express/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ=="], + "@modelcontextprotocol/sdk/express/serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw=="], + "@modelcontextprotocol/sdk/express/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw=="], + "@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.5", "", { "os": "linux", "cpu": "arm" }, "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw=="], + "@modelcontextprotocol/sdk/raw-body/http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg=="], + "@octokit/auth-app/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA=="], + "@octokit/auth-app/@octokit/request/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg=="], + "@octokit/auth-app/@octokit/request-error/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg=="], + "@octokit/auth-oauth-app/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ=="], + "@octokit/auth-oauth-app/@octokit/request/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA=="], + "@octokit/auth-oauth-app/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="], + "@octokit/auth-oauth-device/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="], + "@octokit/auth-oauth-device/@octokit/request/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="], + "@octokit/auth-oauth-device/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.5", "", { "os": "none", "cpu": "x64" }, "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ=="], + "@octokit/auth-oauth-user/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.5", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw=="], + "@octokit/auth-oauth-user/@octokit/request/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg=="], + "@octokit/auth-oauth-user/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA=="], + "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw=="], + "@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ=="], + "@octokit/graphql/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - "@netlify/zip-it-and-ship-it/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="], + "@octokit/graphql/@octokit/request/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@netlify/zip-it-and-ship-it/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + "@octokit/graphql/@octokit/request/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@netlify/zip-it-and-ship-it/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], + "@octokit/graphql/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], - "@netlify/zip-it-and-ship-it/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], + "@octokit/oauth-methods/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - "@netlify/zip-it-and-ship-it/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], + "@octokit/oauth-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@netlify/zip-it-and-ship-it/execa/onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], - "@netlify/zip-it-and-ship-it/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="], - "@netlify/zip-it-and-ship-it/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], - "@netlify/zip-it-and-ship-it/find-up/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@netlify/zip-it-and-ship-it/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@netlify/zip-it-and-ship-it/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "@octokit/plugin-paginate-rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], - "@openauthjs/solid/@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="], + "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], - "@openauthjs/solid/@openauthjs/openauth/aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], - "@openauthjs/solid/@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="], - "@pulumi/pulumi/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + + "@octokit/plugin-retry/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@12.11.0", "", {}, "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="], + + "@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@octokit/rest/@octokit/core/@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], + + "@octokit/rest/@octokit/core/@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="], + + "@octokit/rest/@octokit/core/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], + + "@octokit/rest/@octokit/core/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + + "@octokit/rest/@octokit/core/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], + + "@octokit/rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + + "@opencode-ai/desktop/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], + + "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], + + "@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], + + "@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@pierre/diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], + + "@pierre/diffs/@shikijs/engine-javascript/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], + + "@pierre/diffs/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="], + + "@pierre/diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], + + "@pierre/diffs/shiki/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="], + + "@pierre/diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1hRxtYIJfJSZeM5ivbUXv9hcJP3PWRo5prG/V2sWwiubUKTa+7P62d2qxCW8jiVFX4pgRHhnHNp+qeR7Xl+6kg=="], + + "@pierre/diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-dBMFzzg1QiXqCVQ5ONc0z2ebyoi5BKz+MtfByLm0o5/nbUu3Iz8uaTCa5uzGiscQKm7lVShfZHU1+OG3t5hgwg=="], + + "@pierre/diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-H36qw+oh91Y0s6OlFfdSuQ0Ld+5CgB/VE6gNPK+Hk4VRbVG/XQgkjnt4KzfnnoO6tZPtKJKHPjwebOCfjd6F8A=="], + + "@pierre/diffs/shiki/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], + + "@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + + "@slack/web-api/p-queue/p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="], + + "@solidjs/start/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@solidjs/start/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@solidjs/start/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@solidjs/start/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@solidjs/start/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@solidjs/start/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@solidjs/start/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@solidjs/start/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@solidjs/start/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@solidjs/start/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@solidjs/start/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@solidjs/start/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@solidjs/start/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@solidjs/start/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@solidjs/start/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@solidjs/start/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@solidjs/start/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@solidjs/start/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@solidjs/start/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@solidjs/start/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@solidjs/start/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@solidjs/start/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@solidjs/start/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@solidjs/start/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@solidjs/start/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], "@solidjs/start/shiki/@shikijs/core": ["@shikijs/core@1.29.2", "", { "dependencies": { "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ=="], @@ -3771,41 +4906,47 @@ "@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "archiver-utils/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "archiver-utils/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "archiver-utils/readable-stream/events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "archiver-utils/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "archiver/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "archiver-utils/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "archiver/readable-stream/events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "astro/shiki/@shikijs/core": ["@shikijs/core@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="], - "clipboardy/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + "astro/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="], - "clipboardy/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], + "astro/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA=="], - "clipboardy/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], + "astro/shiki/@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="], - "clipboardy/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], + "astro/shiki/@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="], - "clipboardy/execa/onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], + "astro/shiki/@shikijs/types": ["@shikijs/types@3.15.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw=="], - "clipboardy/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "astro/unstorage/h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="], - "clipboardy/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], + "astro/unstorage/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "colorspace/color/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + "astro/unstorage/ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], - "compress-commons/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="], - "compress-commons/readable-stream/events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], - "crc32-stream/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "crc32-stream/readable-stream/events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -3855,196 +4996,306 @@ "drizzle-kit/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="], - "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - - "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + "esbuild-plugin-copy/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "listhen/@parcel/watcher-wasm/napi-wasm": ["napi-wasm@1.1.3", "", { "bundled": true }, "sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg=="], + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "local-pkg/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "local-pkg/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "nitropack/c12/dotenv": ["dotenv@17.2.1", "", {}, "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ=="], + "js-beautify/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "nitropack/c12/giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], + "js-beautify/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "nitropack/h3/cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="], + "js-beautify/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "nitropack/serve-static/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], + "jsonwebtoken/jws/jwa": ["jwa@1.4.2", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw=="], - "opencode/@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="], + "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "opencode/@openauthjs/openauth/aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], - "opencode/@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "opencontrol/@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="], - "opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="], + "opencontrol/@modelcontextprotocol/sdk/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + + "opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="], - "prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + "parse-bmfont-xml/xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], - "rollup-plugin-visualizer/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="], + "pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], - "rollup-plugin-visualizer/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + "readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "rollup-plugin-visualizer/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + "rimraf/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "rollup-plugin-visualizer/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "rimraf/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "rollup-plugin-visualizer/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "rimraf/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "tar/fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "tw-to-css/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - "unimport/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "tw-to-css/tailwindcss/glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], + "tw-to-css/tailwindcss/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], - "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], + "tw-to-css/tailwindcss/object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], - "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="], + "tw-to-css/tailwindcss/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="], + "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="], + "vitest/vite/esbuild": ["esbuild@0.25.12", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], - "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="], + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="], + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="], + "@actions/artifact/@actions/core/@actions/exec/@actions/io": ["@actions/io@2.0.0", "", {}, "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg=="], - "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="], + "@actions/github/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="], - "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="], + "@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="], - "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="], - "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="], - "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA=="], - "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="], - "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="], - "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.15.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw=="], - "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="], + "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="], + "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA=="], - "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg=="], - "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.782.0", "", { "dependencies": { "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg=="], - "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA=="], - "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="], + "@jsx-email/cli/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], + "@jsx-email/cli/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "wrangler/unenv/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "@jsx-email/cli/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], - "wrangler/unenv/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "@jsx-email/cli/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], - "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "@jsx-email/cli/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], - "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@jsx-email/cli/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], - "zip-stream/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "@jsx-email/cli/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], - "zip-stream/readable-stream/events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "@jsx-email/cli/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + "@jsx-email/cli/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], - "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + "@jsx-email/cli/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], + + "@jsx-email/cli/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], - "@grpc/proto-loader/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@jsx-email/cli/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], - "@grpc/proto-loader/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "@jsx-email/cli/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], - "@grpc/proto-loader/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "@jsx-email/cli/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], - "@grpc/proto-loader/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@jsx-email/cli/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], - "@netlify/zip-it-and-ship-it/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + "@jsx-email/cli/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], - "@netlify/zip-it-and-ship-it/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + "@jsx-email/cli/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], - "@netlify/zip-it-and-ship-it/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@jsx-email/cli/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@netlify/zip-it-and-ship-it/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "@netlify/zip-it-and-ship-it/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "@modelcontextprotocol/sdk/express/body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "@netlify/zip-it-and-ship-it/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "@modelcontextprotocol/sdk/raw-body/http-errors/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "@octokit/auth-app/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/auth-app/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/graphql/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], + + "@octokit/plugin-paginate-rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], + + "@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + + "@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "archiver-utils/readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "archiver-utils/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "astro/unstorage/h3/cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="], + + "astro/unstorage/h3/crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], + + "babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - "archiver/readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "esbuild-plugin-copy/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "clipboardy/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + "js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "clipboardy/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - "colorspace/color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + "opencontrol/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], - "compress-commons/readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "opencontrol/@modelcontextprotocol/sdk/express/content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], - "crc32-stream/readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "opencontrol/@modelcontextprotocol/sdk/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], - "nitropack/c12/giget/nypm": ["nypm@0.6.1", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.2.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w=="], + "opencontrol/@modelcontextprotocol/sdk/express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], - "rollup-plugin-visualizer/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "opencontrol/@modelcontextprotocol/sdk/express/finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], - "rollup-plugin-visualizer/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "opencontrol/@modelcontextprotocol/sdk/express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - "rollup-plugin-visualizer/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "opencontrol/@modelcontextprotocol/sdk/express/http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "rollup-plugin-visualizer/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "opencontrol/@modelcontextprotocol/sdk/express/merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], - "zip-stream/readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "opencontrol/@modelcontextprotocol/sdk/express/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], - "@grpc/proto-loader/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "opencontrol/@modelcontextprotocol/sdk/express/serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], - "@grpc/proto-loader/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "opencontrol/@modelcontextprotocol/sdk/express/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "@grpc/proto-loader/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "opencontrol/@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], - "@netlify/zip-it-and-ship-it/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "opencontrol/@modelcontextprotocol/sdk/raw-body/http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "@netlify/zip-it-and-ship-it/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "pkg-up/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], - "@netlify/zip-it-and-ship-it/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], + + "rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "tw-to-css/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "tw-to-css/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "vitest/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "vitest/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "vitest/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "vitest/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "vitest/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "vitest/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "vitest/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "vitest/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "vitest/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "vitest/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "vitest/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "vitest/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "vitest/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "vitest/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "vitest/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "vitest/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "vitest/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "vitest/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "vitest/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "vitest/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "vitest/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "vitest/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "vitest/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "vitest/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "vitest/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA=="], + + "@jsx-email/cli/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex": ["regex@5.1.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="], - "nitropack/c12/giget/nypm/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "opencontrol/@modelcontextprotocol/sdk/express/body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "opencontrol/@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], - "rollup-plugin-visualizer/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "opencontrol/@modelcontextprotocol/sdk/raw-body/http-errors/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "rollup-plugin-visualizer/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], - "rollup-plugin-visualizer/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "tw-to-css/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], } } diff --git a/bunfig.toml b/bunfig.toml index 6c991e64384..36a21d9332a 100644 --- a/bunfig.toml +++ b/bunfig.toml @@ -1,2 +1,6 @@ [install] -exact = true \ No newline at end of file +exact = true + +[test] +root = "./do-not-run-tests-from-root" + diff --git a/cloud/app/.gitignore b/cloud/app/.gitignore deleted file mode 100644 index 751513ce1b7..00000000000 --- a/cloud/app/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -dist -.wrangler -.output -.vercel -.netlify -.vinxi -app.config.timestamp_*.js - -# Environment -.env -.env*.local - -# dependencies -/node_modules - -# IDEs and editors -/.idea -.project -.classpath -*.launch -.settings/ - -# Temp -gitignore - -# System Files -.DS_Store -Thumbs.db diff --git a/cloud/app/app.config.ts b/cloud/app/app.config.ts deleted file mode 100644 index 0ffa557f906..00000000000 --- a/cloud/app/app.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "@solidjs/start/config" - -export default defineConfig({ - vite: { - server: { - allowedHosts: true, - }, - }, -}) diff --git a/cloud/app/package.json b/cloud/app/package.json deleted file mode 100644 index 1f6bba98a98..00000000000 --- a/cloud/app/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@opencode/cloud-app", - "type": "module", - "scripts": { - "dev": "vinxi dev --host 0.0.0.0", - "build": "vinxi build", - "start": "vinxi start", - "version": "0.5.13" - }, - "dependencies": { - "@ibm/plex": "6.4.1", - "@openauthjs/openauth": "0.0.0-20250322224806", - "@solidjs/meta": "^0.29.4", - "@solidjs/router": "^0.15.0", - "@solidjs/start": "^1.1.0", - "solid-js": "^1.9.5", - "vinxi": "^0.5.7", - "@opencode/cloud-core": "workspace:*" - }, - "engines": { - "node": ">=22" - } -} diff --git a/cloud/app/public/favicon.ico b/cloud/app/public/favicon.ico deleted file mode 100644 index fb282da0719..00000000000 Binary files a/cloud/app/public/favicon.ico and /dev/null differ diff --git a/cloud/app/src/app.tsx b/cloud/app/src/app.tsx deleted file mode 100644 index 504318995f1..00000000000 --- a/cloud/app/src/app.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { MetaProvider, Title } from "@solidjs/meta"; -import { Router } from "@solidjs/router"; -import { FileRoutes } from "@solidjs/start/router"; -import { ErrorBoundary, Suspense } from "solid-js"; -import "@ibm/plex/css/ibm-plex.css"; -import "./app.css"; - -export default function App() { - return ( - ( - - SolidStart - Basic - Something went wrong}> - {props.children} - - - )} - > - - - ); -} diff --git a/cloud/app/src/asset/logo-ornate-dark.svg b/cloud/app/src/asset/logo-ornate-dark.svg deleted file mode 100644 index 2efda934dca..00000000000 --- a/cloud/app/src/asset/logo-ornate-dark.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/cloud/app/src/asset/screenshot-github.webp b/cloud/app/src/asset/screenshot-github.webp deleted file mode 100644 index fda74e641b9..00000000000 Binary files a/cloud/app/src/asset/screenshot-github.webp and /dev/null differ diff --git a/cloud/app/src/asset/screenshot-splash.webp b/cloud/app/src/asset/screenshot-splash.webp deleted file mode 100644 index e900673ef5c..00000000000 Binary files a/cloud/app/src/asset/screenshot-splash.webp and /dev/null differ diff --git a/cloud/app/src/asset/screenshot-vscode.webp b/cloud/app/src/asset/screenshot-vscode.webp deleted file mode 100644 index b8966a6b866..00000000000 Binary files a/cloud/app/src/asset/screenshot-vscode.webp and /dev/null differ diff --git a/cloud/app/src/component/icon.tsx b/cloud/app/src/component/icon.tsx deleted file mode 100644 index 5a565ab9a17..00000000000 --- a/cloud/app/src/component/icon.tsx +++ /dev/null @@ -1,24 +0,0 @@ - -import { JSX } from "solid-js" - - -export function IconCopy(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconCheck(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} diff --git a/cloud/app/src/context/auth.tsx b/cloud/app/src/context/auth.tsx deleted file mode 100644 index 88d3214c11f..00000000000 --- a/cloud/app/src/context/auth.tsx +++ /dev/null @@ -1,109 +0,0 @@ - - -import { useSession } from "vinxi/http" -import { createClient } from "@openauthjs/openauth/client" -import { getRequestEvent } from "solid-js/web" -import { and, Database, eq, inArray } from "@opencode/cloud-core/drizzle/index.js" -import { WorkspaceTable } from "@opencode/cloud-core/schema/workspace.sql.js" -import { UserTable } from "@opencode/cloud-core/schema/user.sql.js" -import { query, redirect } from "@solidjs/router" -import { AccountTable } from "@opencode/cloud-core/schema/account.sql.js" -import { Actor } from "@opencode/cloud-core/actor.js" - -export async function withActor(fn: () => T) { - const actor = await getActor() - return Actor.provide(actor.type, actor.properties, fn) -} - -export const getActor = query(async (): Promise => { - "use server" - const evt = getRequestEvent() - const url = new URL(evt!.request.headers.get("referer") ?? evt!.request.url) - const auth = await useAuthSession() - const [workspaceHint] = url.pathname.split("/").filter((x) => x.length > 0) - if (!workspaceHint) { - if (auth.data.current) { - const current = auth.data.account[auth.data.current] - return { - type: "account", - properties: { - email: current.email, - accountID: current.id, - }, - } - } - if (Object.keys(auth.data.account).length > 0) { - const current = Object.values(auth.data.account)[0] - await auth.update(val => ({ - ...val, - current: current.id, - })) - return { - type: "account", - properties: { - email: current.email, - accountID: current.id, - }, - } - } - return { - type: "public", - properties: {}, - } - } - const accounts = Object.keys(auth.data.account) - const result = await Database.transaction(async (tx) => { - return await tx.select({ - user: UserTable - }) - .from(AccountTable) - .innerJoin(UserTable, and(eq(UserTable.email, AccountTable.email))) - .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, UserTable.workspaceID)) - .where( - and( - inArray(AccountTable.id, accounts), - eq(WorkspaceTable.id, workspaceHint), - ) - ) - .limit(1) - .execute() - .then((x) => x[0]) - }) - if (result) { - return { - type: "user", - properties: { - userID: result.user.id, - workspaceID: result.user.workspaceID, - }, - } - } - throw redirect("/auth/authorize") -}, "actor") - - -export const AuthClient = createClient({ - clientID: "app", - issuer: import.meta.env.VITE_AUTH_URL, -}) - -export interface AuthSession { - account: Record - current?: string -} - -export function useAuthSession() { - - return useSession({ - password: "0".repeat(32), - name: "auth" - }) -} - - -export function AuthProvider() { -} - diff --git a/cloud/app/src/entry-client.tsx b/cloud/app/src/entry-client.tsx deleted file mode 100644 index 0ca4e3c3000..00000000000 --- a/cloud/app/src/entry-client.tsx +++ /dev/null @@ -1,4 +0,0 @@ -// @refresh reload -import { mount, StartClient } from "@solidjs/start/client"; - -mount(() => , document.getElementById("app")!); diff --git a/cloud/app/src/entry-server.tsx b/cloud/app/src/entry-server.tsx deleted file mode 100644 index eb8aea1e879..00000000000 --- a/cloud/app/src/entry-server.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// @refresh reload -import { createHandler, StartServer } from "@solidjs/start/server"; - -export default createHandler(() => ( - ( - - - - - - {assets} - - -
{children}
- {scripts} - - - )} - /> -)); diff --git a/cloud/app/src/global.d.ts b/cloud/app/src/global.d.ts deleted file mode 100644 index dc6f10c226c..00000000000 --- a/cloud/app/src/global.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/cloud/app/src/routes/[...404].tsx b/cloud/app/src/routes/[...404].tsx deleted file mode 100644 index 4ea71ec7fee..00000000000 --- a/cloud/app/src/routes/[...404].tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Title } from "@solidjs/meta"; -import { HttpStatusCode } from "@solidjs/start"; - -export default function NotFound() { - return ( -
- Not Found - -

Page Not Found

-

- Visit{" "} - - start.solidjs.com - {" "} - to learn how to build SolidStart apps. -

-
- ); -} diff --git a/cloud/app/src/routes/[workspaceID].tsx b/cloud/app/src/routes/[workspaceID].tsx deleted file mode 100644 index 706a643233e..00000000000 --- a/cloud/app/src/routes/[workspaceID].tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { createAsync, query } from "@solidjs/router" -import { getActor, withActor } from "~/context/auth" - -const getPosts = query(async () => { - "use server" - return withActor(() => { - return "ok" - }) -}, "posts") - - -export default function () { - const actor = createAsync(async () => getActor()) - return
{JSON.stringify(actor())}
-} diff --git a/cloud/app/src/routes/auth/authorize.ts b/cloud/app/src/routes/auth/authorize.ts deleted file mode 100644 index 166466ef859..00000000000 --- a/cloud/app/src/routes/auth/authorize.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { APIEvent } from "@solidjs/start/server" -import { AuthClient } from "~/context/auth" - -export async function GET(input: APIEvent) { - const result = await AuthClient.authorize(new URL("./callback", input.request.url).toString(), "code") - return Response.redirect(result.url, 302) -} diff --git a/cloud/app/src/routes/auth/callback.ts b/cloud/app/src/routes/auth/callback.ts deleted file mode 100644 index 22dcb2b6d85..00000000000 --- a/cloud/app/src/routes/auth/callback.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { APIEvent } from "@solidjs/start/server" -import { AuthClient, useAuthSession } from "~/context/auth" - -export async function GET(input: APIEvent) { - const url = new URL(input.request.url) - const code = url.searchParams.get("code") - if (!code) throw new Error("No code found") - const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`) - if (result.err) { - throw new Error(result.err.message) - } - const decoded = AuthClient.decode(result.tokens.access, {} as any) - if (decoded.err) throw new Error(decoded.err.message) - const session = await useAuthSession() - const id = decoded.subject.properties.accountID - await session.update((value) => { - return { - ...value, - account: { - [id]: { - id, - email: decoded.subject.properties.email, - }, - }, - current: id, - } - }) - return { - result, - } -} diff --git a/cloud/app/src/routes/index.css b/cloud/app/src/routes/index.css deleted file mode 100644 index 9b0c7009e70..00000000000 --- a/cloud/app/src/routes/index.css +++ /dev/null @@ -1,257 +0,0 @@ -[data-page="home"] { - --color-bg: oklch(0.2097 0.008 274.53); - --color-border: oklch(0.46 0.02 269.88); - --color-text: #ffffff; - --color-text-secondary: oklch(0.72 0.01 270.15); - --color-text-dimmed: hsl(224, 7%, 46%); - padding: var(--space-6); - font-family: var(--font-mono); - color: var(--color-text); - - a { - color: var(--color-text); - text-decoration: underline; - text-underline-offset: var(--space-0-75); - } - - background: var(--color-bg); - position: fixed; - overflow-y: scroll; - inset: 0; - - [data-component="content"] { - max-width: 67.5rem; - margin: 0 auto; - border: 2px solid var(--color-border); - } - - [data-component="top"] { - padding: var(--space-12); - display: flex; - flex-direction: column; - align-items: start; - gap: var(--space-4); - - [data-slot="logo"] { - height: 70px; - } - - [data-slot="title"] { - font-size: var(--font-size-2xl); - text-transform: uppercase; - } - } - - [data-component="cta"] { - height: var(--space-19); - border-top: 2px solid var(--color-border); - display: flex; - - [data-slot="left"] { - display: flex; - padding: 0 var(--space-12); - text-transform: uppercase; - text-decoration: underline; - align-items: center; - justify-content: center; - text-underline-offset: var(--space-0-75); - border-right: 2px solid var(--color-border); - } - - [data-slot="right"] { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: var(--space-2-5); - padding: 0 var(--space-6); - } - - [data-slot="command"] { - all: unset; - display: flex; - align-items: center; - cursor: pointer; - color: var(--color-text-secondary); - font-size: var(--font-size-lg); - font-family: var(--font-mono); - gap: var(--space-2); - } - - [data-slot="highlight"] { - color: var(--color-text); - font-weight: 500; - } - } - - [data-component="features"] { - border-top: 2px solid var(--color-border); - padding: var(--space-12); - - [data-slot="list"] { - padding-left: var(--space-4); - margin: 0; - list-style: disc; - - li { - margin-bottom: var(--space-4); - - strong { - text-transform: uppercase; - font-weight: 600; - } - } - - li:last-child { - margin-bottom: 0; - } - } - } - - [data-component="install"] { - border-top: 2px solid var(--color-border); - display: grid; - grid-template-columns: 1fr 1fr; - grid-template-rows: 1fr 1fr; - - @media (max-width: 40rem) { - grid-template-columns: 1fr; - grid-template-rows: auto; - } - } - - [data-component="title"] { - letter-spacing: -0.03125rem; - text-transform: uppercase; - font-weight: 400; - font-size: var(--font-size-md); - flex-shrink: 0; - color: oklch(0.55 0.02 269.87); - } - - [data-component="method"] { - padding: var(--space-4) var(--space-6); - display: flex; - flex-direction: column; - align-items: start; - gap: var(--space-3); - - &:nth-child(2) { - border-left: 2px solid var(--color-border); - } - - &:nth-child(3) { - border-top: 2px solid var(--color-border); - } - - &:nth-child(4) { - border-top: 2px solid var(--color-border); - border-left: 2px solid var(--color-border); - } - - [data-slot="button"] { - all: unset; - cursor: pointer; - display: flex; - align-items: center; - color: var(--color-text-secondary); - gap: var(--space-2); - - strong { - color: var(--color-text); - font-weight: 500; - } - } - } - - [data-component="screenshots"] { - border-top: 2px solid var(--color-border); - display: grid; - grid-template-columns: 1fr 1fr; - gap: 0; - - [data-slot="left"] { - padding: var(--space-8) var(--space-6); - display: flex; - flex-direction: column; - - img { - width: 100%; - height: auto; - } - } - - [data-slot="right"] { - display: grid; - grid-template-rows: 1fr 1fr; - border-left: 2px solid var(--color-border); - } - - [data-slot="filler"] { - display: flex; - flex-grow: 1; - align-items: center; - justify-content: center; - } - - [data-slot="cell"] { - padding: var(--space-8) var(--space-6); - display: flex; - flex-direction: column; - gap: var(--space-4); - - &:nth-child(2) { - border-top: 2px solid var(--color-border); - } - - img { - width: 80%; - height: auto; - } - } - } - - [data-component="copy-status"] { - [data-slot="copy"] { - display: block; - width: var(--space-4); - height: var(--space-4); - color: var(--color-text-dimmed); - - [data-copied] & { - display: none; - } - } - - [data-slot="check"] { - display: none; - width: var(--space-4); - height: var(--space-4); - color: white; - - [data-copied] & { - display: block; - } - } - } - - [data-component="footer"] { - border-top: 2px solid var(--color-border); - display: grid; - grid-template-columns: 1fr 1fr 1fr; - font-size: var(--font-size-lg); - height: var(--space-20); - - [data-slot="cell"] { - display: flex; - align-items: center; - justify-content: center; - border-right: 2px solid var(--color-border); - text-transform: uppercase; - - &:last-child { - border-right: none; - } - } - } -} diff --git a/cloud/app/src/routes/index.tsx b/cloud/app/src/routes/index.tsx deleted file mode 100644 index 057ddb49e68..00000000000 --- a/cloud/app/src/routes/index.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import { Title } from "@solidjs/meta" -import { onCleanup, onMount } from "solid-js" -import "./index.css" -import logo from "../asset/logo-ornate-dark.svg" -import IMG_SPLASH from "../asset/screenshot-splash.webp" -import IMG_VSCODE from "../asset/screenshot-vscode.webp" -import IMG_GITHUB from "../asset/screenshot-github.webp" -import { IconCopy, IconCheck } from "../component/icon" -import { createAsync, query, redirect, RouteDefinition } from "@solidjs/router" -import { getActor, withActor } from "~/context/auth" -import { Account } from "@opencode/cloud-core/account.js" - -function CopyStatus() { - return ( -
- - -
- ) -} - -const isLoggedIn = query(async () => { - "use server" - const actor = await getActor() - if (actor.type === "account") { - const workspaces = await withActor(() => Account.workspaces()) - throw redirect("/" + workspaces[0].id) - } - return -}, "isLoggedIn") - - - -export default function Home() { - createAsync(() => isLoggedIn(), { - deferStream: true, - }) - onMount(() => { - const commands = document.querySelectorAll("[data-copy]") - for (const button of commands) { - const callback = () => { - const text = button.textContent - if (text) { - navigator.clipboard.writeText(text) - button.setAttribute("data-copied", "") - setTimeout(() => { - button.removeAttribute("data-copied") - }, 1500) - } - } - button.addEventListener("click", callback) - onCleanup(() => { - button.removeEventListener("click", callback) - }) - } - }) - - return ( -
- opencode | AI coding agent built for the terminal -
-
- logo -

The AI coding agent built for the terminal.

-
- -
- -
- -
-
- -
-
    -
  • - Native TUI: A responsive, native, themeable terminal UI. -
  • -
  • - LSP enabled: Automatically loads the right LSPs for the LLM. -
  • -
  • - Multi-session: Start multiple agents in parallel on the same project. -
  • -
  • - Shareable links: Share a link to any sessions for reference or to debug. -
  • -
  • - Claude Pro: Log in with Anthropic to use your Claude Pro or Max account. -
  • -
  • - Use any model: Supports 75+ LLM providers through{" "} - Models.dev, including local models. -
  • -
-
- -
-
-

npm

- -
-
-

bun

- -
-
-

homebrew

- -
-
-

paru

- -
-
- -
-
-
opencode TUI with tokyonight theme
-
- opencode TUI with tokyonight theme -
-
-
-
-
opencode in VS Code
-
- opencode in VS Code -
-
-
-
opencode in GitHub
-
- opencode in GitHub -
-
-
-
- - -
-
- ) -} diff --git a/cloud/app/src/style/base.css b/cloud/app/src/style/base.css deleted file mode 100644 index 2c95cdbb76a..00000000000 --- a/cloud/app/src/style/base.css +++ /dev/null @@ -1,8 +0,0 @@ -html { - color-scheme: dark; - line-height: 1; -} - -body { - font-family: var(--font-sans); -} diff --git a/cloud/app/src/style/token/color.css b/cloud/app/src/style/token/color.css deleted file mode 100644 index 5382321e332..00000000000 --- a/cloud/app/src/style/token/color.css +++ /dev/null @@ -1,90 +0,0 @@ -body { - --color-white: #ffffff; - --color-black: #000000; -} - -[data-color-mode="dark"] { - /* OpenCode theme colors */ - --color-bg: #0c0c0e; - --color-bg-surface: #161618; - --color-bg-elevated: #1c1c1f; - - --color-text: #ffffff; - --color-text-muted: #a1a1a6; - --color-text-disabled: #68686f; - - --color-accent: #007aff; - --color-accent-hover: #0056b3; - --color-accent-active: #004085; - - --color-success: #30d158; - --color-warning: #ff9f0a; - --color-danger: #ff453a; - - --color-border: #38383a; - --color-border-muted: #2c2c2e; - - /* Button colors */ - --color-primary: var(--color-accent); - --color-primary-hover: var(--color-accent-hover); - --color-primary-active: var(--color-accent-active); - --color-primary-text: #ffffff; - - --color-danger: #ff453a; - --color-danger-hover: #d70015; - --color-danger-active: #a50011; - --color-danger-text: #ffffff; - - --color-warning: #ff9f0a; - --color-warning-hover: #cc7f08; - --color-warning-active: #995f06; - --color-warning-text: #000000; - - /* Surface colors */ - --color-surface: var(--color-bg-surface); - --color-surface-hover: var(--color-bg-elevated); - --color-border: var(--color-border); -} - -[data-color-mode="light"] { - /* OpenCode light theme colors */ - --color-bg: #ffffff; - --color-bg-surface: #f5f5f7; - --color-bg-elevated: #ffffff; - - --color-text: #1d1d1f; - --color-text-muted: #6e6e73; - --color-text-disabled: #86868b; - - --color-accent: #007aff; - --color-accent-hover: #0056b3; - --color-accent-active: #004085; - - --color-success: #30d158; - --color-warning: #ff9f0a; - --color-danger: #ff3b30; - - --color-border: #d2d2d7; - --color-border-muted: #e5e5ea; - - /* Button colors */ - --color-primary: var(--color-accent); - --color-primary-hover: var(--color-accent-hover); - --color-primary-active: var(--color-accent-active); - --color-primary-text: #ffffff; - - --color-danger: #ff3b30; - --color-danger-hover: #d70015; - --color-danger-active: #a50011; - --color-danger-text: #ffffff; - - --color-warning: #ff9f0a; - --color-warning-hover: #cc7f08; - --color-warning-active: #995f06; - --color-warning-text: #000000; - - /* Surface colors */ - --color-surface: var(--color-bg-surface); - --color-surface-hover: var(--color-bg-elevated); - --color-border: var(--color-border); -} diff --git a/cloud/app/src/style/token/font.css b/cloud/app/src/style/token/font.css deleted file mode 100644 index 1852af5b0bb..00000000000 --- a/cloud/app/src/style/token/font.css +++ /dev/null @@ -1,18 +0,0 @@ -body { - --font-size-2xs: 0.6875rem; - --font-size-xs: 0.75rem; - --font-size-sm: 0.8125rem; - --font-size-md: 0.9375rem; - --font-size-lg: 1.125rem; - --font-size-xl: 1.25rem; - --font-size-2xl: 1.5rem; - --font-size-3xl: 1.875rem; - --font-size-4xl: 2.25rem; - --font-size-5xl: 3rem; - --font-size-6xl: 3.75rem; - --font-size-7xl: 4.5rem; - --font-size-8xl: 6rem; - --font-size-9xl: 8rem; - --font-mono: IBM Plex Mono; - --font-sans: Inter; -} diff --git a/cloud/app/src/style/token/space.css b/cloud/app/src/style/token/space.css deleted file mode 100644 index dcd871c5fd5..00000000000 --- a/cloud/app/src/style/token/space.css +++ /dev/null @@ -1,42 +0,0 @@ -body { - --space-0: 0; - --space-px: 1px; - --space-0-5: 0.125rem; - --space-0-75: 0.1875rem; - --space-1: 0.25rem; - --space-1-5: 0.375rem; - --space-2: 0.5rem; - --space-2-5: 0.625rem; - --space-3: 0.75rem; - --space-3-5: 0.875rem; - --space-4: 1rem; - --space-4-5: 1.125rem; - --space-5: 1.25rem; - --space-6: 1.5rem; - --space-7: 1.75rem; - --space-8: 2rem; - --space-9: 2.25rem; - --space-10: 2.5rem; - --space-11: 2.75rem; - --space-12: 3rem; - --space-14: 3.5rem; - --space-16: 4rem; - --space-17: 4.25rem; - --space-18: 4.5rem; - --space-19: 4.75rem; - --space-20: 5rem; - --space-24: 6rem; - --space-28: 7rem; - --space-32: 8rem; - --space-36: 9rem; - --space-40: 10rem; - --space-44: 11rem; - --space-48: 12rem; - --space-52: 13rem; - --space-56: 14rem; - --space-60: 15rem; - --space-64: 16rem; - --space-72: 18rem; - --space-80: 20rem; - --space-96: 24rem; -} diff --git a/cloud/app/tsconfig.json b/cloud/app/tsconfig.json deleted file mode 100644 index 7d5871a07ad..00000000000 --- a/cloud/app/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - "allowJs": true, - "strict": true, - "noEmit": true, - "types": ["vinxi/types/client"], - "isolatedModules": true, - "paths": { - "~/*": ["./src/*"] - } - } -} diff --git a/cloud/core/migrations/0000_amused_mojo.sql b/cloud/core/migrations/0000_amused_mojo.sql deleted file mode 100644 index 75441ad2456..00000000000 --- a/cloud/core/migrations/0000_amused_mojo.sql +++ /dev/null @@ -1,66 +0,0 @@ -CREATE TABLE "billing" ( - "id" varchar(30) NOT NULL, - "workspace_id" varchar(30) NOT NULL, - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone, - "customer_id" varchar(255), - "payment_method_id" varchar(255), - "payment_method_last4" varchar(4), - "balance" bigint NOT NULL, - "reload" boolean, - CONSTRAINT "billing_workspace_id_id_pk" PRIMARY KEY("workspace_id","id") -); ---> statement-breakpoint -CREATE TABLE "payment" ( - "id" varchar(30) NOT NULL, - "workspace_id" varchar(30) NOT NULL, - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone, - "customer_id" varchar(255), - "payment_id" varchar(255), - "amount" bigint NOT NULL, - CONSTRAINT "payment_workspace_id_id_pk" PRIMARY KEY("workspace_id","id") -); ---> statement-breakpoint -CREATE TABLE "usage" ( - "id" varchar(30) NOT NULL, - "workspace_id" varchar(30) NOT NULL, - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone, - "request_id" varchar(255), - "model" varchar(255) NOT NULL, - "input_tokens" integer NOT NULL, - "output_tokens" integer NOT NULL, - "reasoning_tokens" integer, - "cache_read_tokens" integer, - "cache_write_tokens" integer, - "cost" bigint NOT NULL, - CONSTRAINT "usage_workspace_id_id_pk" PRIMARY KEY("workspace_id","id") -); ---> statement-breakpoint -CREATE TABLE "user" ( - "id" varchar(30) NOT NULL, - "workspace_id" varchar(30) NOT NULL, - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone, - "email" text NOT NULL, - "name" varchar(255) NOT NULL, - "time_seen" timestamp with time zone, - "color" integer, - CONSTRAINT "user_workspace_id_id_pk" PRIMARY KEY("workspace_id","id") -); ---> statement-breakpoint -CREATE TABLE "workspace" ( - "id" varchar(30) PRIMARY KEY NOT NULL, - "slug" varchar(255), - "name" varchar(255), - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone -); ---> statement-breakpoint -ALTER TABLE "billing" ADD CONSTRAINT "billing_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "payment" ADD CONSTRAINT "payment_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "usage" ADD CONSTRAINT "usage_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "user" ADD CONSTRAINT "user_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -CREATE UNIQUE INDEX "user_email" ON "user" USING btree ("workspace_id","email");--> statement-breakpoint -CREATE UNIQUE INDEX "slug" ON "workspace" USING btree ("slug"); \ No newline at end of file diff --git a/cloud/core/migrations/0001_thankful_chat.sql b/cloud/core/migrations/0001_thankful_chat.sql deleted file mode 100644 index 9c66a6ac4fc..00000000000 --- a/cloud/core/migrations/0001_thankful_chat.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE "account" ( - "id" varchar(30) NOT NULL, - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone, - "email" varchar(255) NOT NULL -); ---> statement-breakpoint -CREATE UNIQUE INDEX "email" ON "account" USING btree ("email"); \ No newline at end of file diff --git a/cloud/core/migrations/0002_stale_jackal.sql b/cloud/core/migrations/0002_stale_jackal.sql deleted file mode 100644 index 267dff27353..00000000000 --- a/cloud/core/migrations/0002_stale_jackal.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE "key" ( - "id" varchar(30) NOT NULL, - "workspace_id" varchar(30) NOT NULL, - "time_created" timestamp with time zone DEFAULT now() NOT NULL, - "time_deleted" timestamp with time zone, - "user_id" text NOT NULL, - "name" varchar(255) NOT NULL, - "key" varchar(255) NOT NULL, - "time_used" timestamp with time zone, - CONSTRAINT "key_workspace_id_id_pk" PRIMARY KEY("workspace_id","id") -); ---> statement-breakpoint -ALTER TABLE "key" ADD CONSTRAINT "key_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -CREATE UNIQUE INDEX "global_key" ON "key" USING btree ("key"); \ No newline at end of file diff --git a/cloud/core/migrations/0003_tranquil_spencer_smythe.sql b/cloud/core/migrations/0003_tranquil_spencer_smythe.sql deleted file mode 100644 index 4f57f779fb2..00000000000 --- a/cloud/core/migrations/0003_tranquil_spencer_smythe.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "usage" DROP COLUMN "request_id"; \ No newline at end of file diff --git a/cloud/core/migrations/meta/0000_snapshot.json b/cloud/core/migrations/meta/0000_snapshot.json deleted file mode 100644 index 3b86bed25ad..00000000000 --- a/cloud/core/migrations/meta/0000_snapshot.json +++ /dev/null @@ -1,461 +0,0 @@ -{ - "id": "9b5cec8c-8b59-4d7a-bb5c-76ade1c83d6f", - "prevId": "00000000-0000-0000-0000-000000000000", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.billing": { - "name": "billing", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "billing_workspace_id_workspace_id_fk": { - "name": "billing_workspace_id_workspace_id_fk", - "tableFrom": "billing", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payment": { - "name": "payment", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "payment_workspace_id_workspace_id_fk": { - "name": "payment_workspace_id_workspace_id_fk", - "tableFrom": "payment", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.usage": { - "name": "usage", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "request_id": { - "name": "request_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "input_tokens": { - "name": "input_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "output_tokens": { - "name": "output_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "usage_workspace_id_workspace_id_fk": { - "name": "usage_workspace_id_workspace_id_fk", - "tableFrom": "usage", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "user_workspace_id_workspace_id_fk": { - "name": "user_workspace_id_workspace_id_fk", - "tableFrom": "user", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace": { - "name": "workspace", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": true, - "notNull": true - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/cloud/core/migrations/meta/0001_snapshot.json b/cloud/core/migrations/meta/0001_snapshot.json deleted file mode 100644 index 69d66ebc6d2..00000000000 --- a/cloud/core/migrations/meta/0001_snapshot.json +++ /dev/null @@ -1,515 +0,0 @@ -{ - "id": "bf9e9084-4073-4ecb-8e56-5610816c9589", - "prevId": "9b5cec8c-8b59-4d7a-bb5c-76ade1c83d6f", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "email": { - "name": "email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.billing": { - "name": "billing", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "billing_workspace_id_workspace_id_fk": { - "name": "billing_workspace_id_workspace_id_fk", - "tableFrom": "billing", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payment": { - "name": "payment", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "payment_workspace_id_workspace_id_fk": { - "name": "payment_workspace_id_workspace_id_fk", - "tableFrom": "payment", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.usage": { - "name": "usage", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "request_id": { - "name": "request_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "input_tokens": { - "name": "input_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "output_tokens": { - "name": "output_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "usage_workspace_id_workspace_id_fk": { - "name": "usage_workspace_id_workspace_id_fk", - "tableFrom": "usage", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "user_workspace_id_workspace_id_fk": { - "name": "user_workspace_id_workspace_id_fk", - "tableFrom": "user", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace": { - "name": "workspace", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": true, - "notNull": true - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/cloud/core/migrations/meta/0002_snapshot.json b/cloud/core/migrations/meta/0002_snapshot.json deleted file mode 100644 index 7d970ab022b..00000000000 --- a/cloud/core/migrations/meta/0002_snapshot.json +++ /dev/null @@ -1,615 +0,0 @@ -{ - "id": "351e4956-74e0-4282-a23b-02f1a73fa38c", - "prevId": "bf9e9084-4073-4ecb-8e56-5610816c9589", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "email": { - "name": "email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.billing": { - "name": "billing", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "billing_workspace_id_workspace_id_fk": { - "name": "billing_workspace_id_workspace_id_fk", - "tableFrom": "billing", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payment": { - "name": "payment", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "payment_workspace_id_workspace_id_fk": { - "name": "payment_workspace_id_workspace_id_fk", - "tableFrom": "payment", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.usage": { - "name": "usage", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "request_id": { - "name": "request_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "input_tokens": { - "name": "input_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "output_tokens": { - "name": "output_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "usage_workspace_id_workspace_id_fk": { - "name": "usage_workspace_id_workspace_id_fk", - "tableFrom": "usage", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.key": { - "name": "key", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "time_used": { - "name": "time_used", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": [ - { - "expression": "key", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "key_workspace_id_workspace_id_fk": { - "name": "key_workspace_id_workspace_id_fk", - "tableFrom": "key", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "user_workspace_id_workspace_id_fk": { - "name": "user_workspace_id_workspace_id_fk", - "tableFrom": "user", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace": { - "name": "workspace", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": true, - "notNull": true - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/cloud/core/migrations/meta/0003_snapshot.json b/cloud/core/migrations/meta/0003_snapshot.json deleted file mode 100644 index e1202ddbfc5..00000000000 --- a/cloud/core/migrations/meta/0003_snapshot.json +++ /dev/null @@ -1,609 +0,0 @@ -{ - "id": "fa935883-9e51-4811-90c7-8967eefe458c", - "prevId": "351e4956-74e0-4282-a23b-02f1a73fa38c", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "email": { - "name": "email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.billing": { - "name": "billing", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "billing_workspace_id_workspace_id_fk": { - "name": "billing_workspace_id_workspace_id_fk", - "tableFrom": "billing", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payment": { - "name": "payment", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "payment_workspace_id_workspace_id_fk": { - "name": "payment_workspace_id_workspace_id_fk", - "tableFrom": "payment", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.usage": { - "name": "usage", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "input_tokens": { - "name": "input_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "output_tokens": { - "name": "output_tokens", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "usage_workspace_id_workspace_id_fk": { - "name": "usage_workspace_id_workspace_id_fk", - "tableFrom": "usage", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.key": { - "name": "key", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "time_used": { - "name": "time_used", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": [ - { - "expression": "key", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "key_workspace_id_workspace_id_fk": { - "name": "key_workspace_id_workspace_id_fk", - "tableFrom": "key", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "user_workspace_id_workspace_id_fk": { - "name": "user_workspace_id_workspace_id_fk", - "tableFrom": "user", - "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace": { - "name": "workspace", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": true, - "notNull": true - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/cloud/core/migrations/meta/_journal.json b/cloud/core/migrations/meta/_journal.json deleted file mode 100644 index ceba11e26bb..00000000000 --- a/cloud/core/migrations/meta/_journal.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1754518198186, - "tag": "0000_amused_mojo", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1754609655262, - "tag": "0001_thankful_chat", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1754627626945, - "tag": "0002_stale_jackal", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1754672464106, - "tag": "0003_tranquil_spencer_smythe", - "breakpoints": true - } - ] -} \ No newline at end of file diff --git a/cloud/core/package.json b/cloud/core/package.json deleted file mode 100644 index a13a2b166ed..00000000000 --- a/cloud/core/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/package.json", - "name": "@opencode/cloud-core", - "version": "0.5.13", - "private": true, - "type": "module", - "dependencies": { - "@aws-sdk/client-sts": "3.782.0", - "drizzle-orm": "0.41.0", - "postgres": "3.4.7", - "stripe": "18.0.0", - "ulid": "3.0.0" - }, - "exports": { - "./*": "./src/*" - }, - "scripts": { - "db": "sst shell drizzle-kit" - }, - "devDependencies": { - "drizzle-kit": "0.30.5" - } -} diff --git a/cloud/core/src/account.ts b/cloud/core/src/account.ts deleted file mode 100644 index cb123e0485d..00000000000 --- a/cloud/core/src/account.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { z } from "zod" -import { and, eq, getTableColumns, isNull } from "drizzle-orm" -import { fn } from "./util/fn" -import { Database } from "./drizzle" -import { Identifier } from "./identifier" -import { AccountTable } from "./schema/account.sql" -import { Actor } from "./actor" -import { WorkspaceTable } from "./schema/workspace.sql" -import { UserTable } from "./schema/user.sql" - -export namespace Account { - export const create = fn( - z.object({ - email: z.string().email(), - id: z.string().optional(), - }), - async (input) => - Database.transaction(async (tx) => { - const id = input.id ?? Identifier.create("account") - await tx.insert(AccountTable).values({ - id, - email: input.email, - }) - return id - }), - ) - - export const fromID = fn(z.string(), async (id) => - Database.transaction(async (tx) => { - return tx - .select() - .from(AccountTable) - .where(eq(AccountTable.id, id)) - .execute() - .then((rows) => rows[0]) - }), - ) - - export const fromEmail = fn(z.string().email(), async (email) => - Database.transaction(async (tx) => { - return tx - .select() - .from(AccountTable) - .where(eq(AccountTable.email, email)) - .execute() - .then((rows) => rows[0]) - }), - ) - - export const workspaces = async () => { - const actor = Actor.assert("account") - return Database.transaction(async (tx) => - tx - .select(getTableColumns(WorkspaceTable)) - .from(WorkspaceTable) - .innerJoin(UserTable, eq(UserTable.workspaceID, WorkspaceTable.id)) - .where( - and( - eq(UserTable.email, actor.properties.email), - isNull(UserTable.timeDeleted), - isNull(WorkspaceTable.timeDeleted), - ), - ) - .execute(), - ) - } -} diff --git a/cloud/core/src/actor.ts b/cloud/core/src/actor.ts deleted file mode 100644 index 0d13f7216f2..00000000000 --- a/cloud/core/src/actor.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Context } from "./context" -import { Log } from "./util/log" - -export namespace Actor { - interface Account { - type: "account" - properties: { - accountID: string - email: string - } - } - - interface Public { - type: "public" - properties: {} - } - - interface User { - type: "user" - properties: { - userID: string - workspaceID: string - } - } - - interface System { - type: "system" - properties: { - workspaceID: string - } - } - - export type Info = Account | Public | User | System - - const ctx = Context.create() - export const use = ctx.use - - const log = Log.create().tag("namespace", "actor") - - export function provide( - type: T, - properties: Extract["properties"], - cb: () => R, - ) { - return ctx.provide( - { - type, - properties, - } as any, - () => { - return Log.provide({ ...properties }, () => { - log.info("provided") - return cb() - }) - }, - ) - } - - export function assert(type: T) { - const actor = use() - if (actor.type !== type) { - throw new Error(`Expected actor type ${type}, got ${actor.type}`) - } - return actor as Extract - } - - export function workspace() { - const actor = use() - if ("workspaceID" in actor.properties) { - return actor.properties.workspaceID - } - throw new Error(`actor of type "${actor.type}" is not associated with a workspace`) - } -} diff --git a/cloud/core/src/billing.ts b/cloud/core/src/billing.ts deleted file mode 100644 index 1a7bb294659..00000000000 --- a/cloud/core/src/billing.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Resource } from "sst" -import { Stripe } from "stripe" -import { Database, eq, sql } from "./drizzle" -import { BillingTable, UsageTable } from "./schema/billing.sql" -import { Actor } from "./actor" -import { fn } from "./util/fn" -import { z } from "zod" -import { Identifier } from "./identifier" -import { centsToMicroCents } from "./util/price" - -export namespace Billing { - export const stripe = () => - new Stripe(Resource.STRIPE_SECRET_KEY.value, { - apiVersion: "2025-03-31.basil", - }) - - export const get = async () => { - return Database.use(async (tx) => - tx - .select({ - customerID: BillingTable.customerID, - paymentMethodID: BillingTable.paymentMethodID, - balance: BillingTable.balance, - reload: BillingTable.reload, - }) - .from(BillingTable) - .where(eq(BillingTable.workspaceID, Actor.workspace())) - .then((r) => r[0]), - ) - } - - export const consume = fn( - z.object({ - requestID: z.string().optional(), - model: z.string(), - inputTokens: z.number(), - outputTokens: z.number(), - reasoningTokens: z.number().optional(), - cacheReadTokens: z.number().optional(), - cacheWriteTokens: z.number().optional(), - costInCents: z.number(), - }), - async (input) => { - const workspaceID = Actor.workspace() - const cost = centsToMicroCents(input.costInCents) - - return await Database.transaction(async (tx) => { - await tx.insert(UsageTable).values({ - workspaceID, - id: Identifier.create("usage"), - requestID: input.requestID, - model: input.model, - inputTokens: input.inputTokens, - outputTokens: input.outputTokens, - reasoningTokens: input.reasoningTokens, - cacheReadTokens: input.cacheReadTokens, - cacheWriteTokens: input.cacheWriteTokens, - cost, - }) - const [updated] = await tx - .update(BillingTable) - .set({ - balance: sql`${BillingTable.balance} - ${cost}`, - }) - .where(eq(BillingTable.workspaceID, workspaceID)) - .returning() - return updated.balance - }) - }, - ) -} diff --git a/cloud/core/src/drizzle/index.ts b/cloud/core/src/drizzle/index.ts deleted file mode 100644 index 46fe93ac4ff..00000000000 --- a/cloud/core/src/drizzle/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { drizzle } from "drizzle-orm/postgres-js" -import { Resource } from "sst" -export * from "drizzle-orm" -import postgres from "postgres" - -const createClient = memo(() => { - const client = postgres({ - idle_timeout: 30000, - connect_timeout: 30000, - host: Resource.Database.host, - database: Resource.Database.database, - user: Resource.Database.username, - password: Resource.Database.password, - port: Resource.Database.port, - ssl: { - rejectUnauthorized: false, - }, - max: 1, - }) - - return drizzle(client, {}) -}) - -import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core" -import type { ExtractTablesWithRelations } from "drizzle-orm" -import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js" -import { Context } from "../context" -import { memo } from "../util/memo" - -export namespace Database { - export type Transaction = PgTransaction< - PostgresJsQueryResultHKT, - Record, - ExtractTablesWithRelations> - > - - export type TxOrDb = Transaction | ReturnType - - const TransactionContext = Context.create<{ - tx: TxOrDb - effects: (() => void | Promise)[] - }>() - - export async function use(callback: (trx: TxOrDb) => Promise) { - try { - const { tx } = TransactionContext.use() - return tx.transaction(callback) - } catch (err) { - if (err instanceof Context.NotFound) { - const client = createClient() - const effects: (() => void | Promise)[] = [] - const result = await TransactionContext.provide( - { - effects, - tx: client, - }, - () => callback(client), - ) - await Promise.all(effects.map((x) => x())) - return result - } - throw err - } - } - export async function fn(callback: (input: Input, trx: TxOrDb) => Promise) { - return (input: Input) => use(async (tx) => callback(input, tx)) - } - - export async function effect(effect: () => any | Promise) { - try { - const { effects } = TransactionContext.use() - effects.push(effect) - } catch { - await effect() - } - } - - export async function transaction(callback: (tx: TxOrDb) => Promise, config?: PgTransactionConfig) { - try { - const { tx } = TransactionContext.use() - return callback(tx) - } catch (err) { - if (err instanceof Context.NotFound) { - const client = createClient() - const effects: (() => void | Promise)[] = [] - const result = await client.transaction(async (tx) => { - return TransactionContext.provide({ tx, effects }, () => callback(tx)) - }, config) - await Promise.all(effects.map((x) => x())) - return result - } - throw err - } - } -} diff --git a/cloud/core/src/drizzle/types.ts b/cloud/core/src/drizzle/types.ts deleted file mode 100644 index 5ae95d0112c..00000000000 --- a/cloud/core/src/drizzle/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { bigint, timestamp, varchar } from "drizzle-orm/pg-core" - -export const ulid = (name: string) => varchar(name, { length: 30 }) - -export const workspaceColumns = { - get id() { - return ulid("id").notNull() - }, - get workspaceID() { - return ulid("workspace_id").notNull() - }, -} - -export const id = () => ulid("id").notNull() - -export const utc = (name: string) => - timestamp(name, { - withTimezone: true, - }) - -export const currency = (name: string) => - bigint(name, { - mode: "number", - }) - -export const timestamps = { - timeCreated: utc("time_created").notNull().defaultNow(), - timeDeleted: utc("time_deleted"), -} diff --git a/cloud/core/src/identifier.ts b/cloud/core/src/identifier.ts deleted file mode 100644 index f8e73852ef3..00000000000 --- a/cloud/core/src/identifier.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ulid } from "ulid" -import { z } from "zod" - -export namespace Identifier { - const prefixes = { - account: "acc", - billing: "bil", - key: "key", - payment: "pay", - usage: "usg", - user: "usr", - workspace: "wrk", - } as const - - export function create(prefix: keyof typeof prefixes, given?: string): string { - if (given) { - if (given.startsWith(prefixes[prefix])) return given - throw new Error(`ID ${given} does not start with ${prefixes[prefix]}`) - } - return [prefixes[prefix], ulid()].join("_") - } - - export function schema(prefix: keyof typeof prefixes) { - return z.string().startsWith(prefixes[prefix]) - } -} diff --git a/cloud/core/src/schema/account.sql.ts b/cloud/core/src/schema/account.sql.ts deleted file mode 100644 index 1733f0a1568..00000000000 --- a/cloud/core/src/schema/account.sql.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { pgTable, uniqueIndex, varchar } from "drizzle-orm/pg-core" -import { id, timestamps } from "../drizzle/types" - -export const AccountTable = pgTable( - "account", - { - id: id(), - ...timestamps, - email: varchar("email", { length: 255 }).notNull(), - }, - (table) => [uniqueIndex("email").on(table.email)], -) diff --git a/cloud/core/src/schema/billing.sql.ts b/cloud/core/src/schema/billing.sql.ts deleted file mode 100644 index 96b29f5def6..00000000000 --- a/cloud/core/src/schema/billing.sql.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { bigint, boolean, integer, pgTable, varchar } from "drizzle-orm/pg-core" -import { timestamps, workspaceColumns } from "../drizzle/types" -import { workspaceIndexes } from "./workspace.sql" - -export const BillingTable = pgTable( - "billing", - { - ...workspaceColumns, - ...timestamps, - customerID: varchar("customer_id", { length: 255 }), - paymentMethodID: varchar("payment_method_id", { length: 255 }), - paymentMethodLast4: varchar("payment_method_last4", { length: 4 }), - balance: bigint("balance", { mode: "number" }).notNull(), - reload: boolean("reload"), - }, - (table) => [...workspaceIndexes(table)], -) - -export const PaymentTable = pgTable( - "payment", - { - ...workspaceColumns, - ...timestamps, - customerID: varchar("customer_id", { length: 255 }), - paymentID: varchar("payment_id", { length: 255 }), - amount: bigint("amount", { mode: "number" }).notNull(), - }, - (table) => [...workspaceIndexes(table)], -) - -export const UsageTable = pgTable( - "usage", - { - ...workspaceColumns, - ...timestamps, - model: varchar("model", { length: 255 }).notNull(), - inputTokens: integer("input_tokens").notNull(), - outputTokens: integer("output_tokens").notNull(), - reasoningTokens: integer("reasoning_tokens"), - cacheReadTokens: integer("cache_read_tokens"), - cacheWriteTokens: integer("cache_write_tokens"), - cost: bigint("cost", { mode: "number" }).notNull(), - }, - (table) => [...workspaceIndexes(table)], -) diff --git a/cloud/core/src/schema/key.sql.ts b/cloud/core/src/schema/key.sql.ts deleted file mode 100644 index 240736b86d7..00000000000 --- a/cloud/core/src/schema/key.sql.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { text, pgTable, varchar, uniqueIndex } from "drizzle-orm/pg-core" -import { timestamps, utc, workspaceColumns } from "../drizzle/types" -import { workspaceIndexes } from "./workspace.sql" - -export const KeyTable = pgTable( - "key", - { - ...workspaceColumns, - ...timestamps, - userID: text("user_id").notNull(), - name: varchar("name", { length: 255 }).notNull(), - key: varchar("key", { length: 255 }).notNull(), - timeUsed: utc("time_used"), - }, - (table) => [...workspaceIndexes(table), uniqueIndex("global_key").on(table.key)], -) diff --git a/cloud/core/src/schema/user.sql.ts b/cloud/core/src/schema/user.sql.ts deleted file mode 100644 index 34cbd6bebc6..00000000000 --- a/cloud/core/src/schema/user.sql.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { text, pgTable, uniqueIndex, varchar, integer } from "drizzle-orm/pg-core" -import { timestamps, utc, workspaceColumns } from "../drizzle/types" -import { workspaceIndexes } from "./workspace.sql" - -export const UserTable = pgTable( - "user", - { - ...workspaceColumns, - ...timestamps, - email: text("email").notNull(), - name: varchar("name", { length: 255 }).notNull(), - timeSeen: utc("time_seen"), - color: integer("color"), - }, - (table) => [...workspaceIndexes(table), uniqueIndex("user_email").on(table.workspaceID, table.email)], -) diff --git a/cloud/core/src/schema/workspace.sql.ts b/cloud/core/src/schema/workspace.sql.ts deleted file mode 100644 index 3e9379e1f53..00000000000 --- a/cloud/core/src/schema/workspace.sql.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { primaryKey, foreignKey, pgTable, uniqueIndex, varchar } from "drizzle-orm/pg-core" -import { timestamps, ulid } from "../drizzle/types" - -export const WorkspaceTable = pgTable( - "workspace", - { - id: ulid("id").notNull().primaryKey(), - slug: varchar("slug", { length: 255 }), - name: varchar("name", { length: 255 }), - ...timestamps, - }, - (table) => [uniqueIndex("slug").on(table.slug)], -) - -export function workspaceIndexes(table: any) { - return [ - primaryKey({ - columns: [table.workspaceID, table.id], - }), - foreignKey({ - foreignColumns: [WorkspaceTable.id], - columns: [table.workspaceID], - }), - ] -} diff --git a/cloud/core/src/util/fn.ts b/cloud/core/src/util/fn.ts deleted file mode 100644 index 038a507197d..00000000000 --- a/cloud/core/src/util/fn.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from "zod" - -export function fn( - schema: T, - cb: (input: z.output) => Result, -) { - const result = (input: z.input) => { - const parsed = schema.parse(input) - return cb(parsed) - } - result.force = (input: z.input) => cb(input) - result.schema = schema - return result -} diff --git a/cloud/core/src/util/memo.ts b/cloud/core/src/util/memo.ts deleted file mode 100644 index 3c84cf1fb46..00000000000 --- a/cloud/core/src/util/memo.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function memo(fn: () => T) { - let value: T | undefined - let loaded = false - - return (): T => { - if (loaded) return value as T - loaded = true - value = fn() - return value as T - } -} diff --git a/cloud/core/src/workspace.ts b/cloud/core/src/workspace.ts deleted file mode 100644 index 532b22963ef..00000000000 --- a/cloud/core/src/workspace.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { z } from "zod" -import { fn } from "./util/fn" -import { centsToMicroCents } from "./util/price" -import { Actor } from "./actor" -import { Database, eq } from "./drizzle" -import { Identifier } from "./identifier" -import { UserTable } from "./schema/user.sql" -import { BillingTable } from "./schema/billing.sql" -import { WorkspaceTable } from "./schema/workspace.sql" - -export namespace Workspace { - export const create = fn(z.void(), async () => { - const account = Actor.assert("account") - const workspaceID = Identifier.create("workspace") - await Database.transaction(async (tx) => { - await tx.insert(WorkspaceTable).values({ - id: workspaceID, - }) - await tx.insert(UserTable).values({ - workspaceID, - id: Identifier.create("user"), - email: account.properties.email, - name: "", - }) - await tx.insert(BillingTable).values({ - workspaceID, - id: Identifier.create("billing"), - balance: centsToMicroCents(100), - }) - }) - return workspaceID - }) - - export async function list() { - const account = Actor.assert("account") - return Database.use(async (tx) => { - return tx - .select({ - id: WorkspaceTable.id, - slug: WorkspaceTable.slug, - name: WorkspaceTable.name, - }) - .from(UserTable) - .innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id)) - .where(eq(UserTable.email, account.properties.email)) - }) - } -} diff --git a/cloud/function/package.json b/cloud/function/package.json deleted file mode 100644 index 72d7b5db829..00000000000 --- a/cloud/function/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@opencode/cloud-function", - "version": "0.5.13", - "$schema": "https://json.schemastore.org/package.json", - "private": true, - "type": "module", - "devDependencies": { - "@cloudflare/workers-types": "4.20250522.0", - "@types/node": "catalog:", - "openai": "5.11.0", - "typescript": "catalog:" - }, - "dependencies": { - "@ai-sdk/anthropic": "2.0.0", - "@ai-sdk/openai": "2.0.2", - "@ai-sdk/openai-compatible": "1.0.1", - "@hono/zod-validator": "catalog:", - "@openauthjs/openauth": "0.0.0-20250322224806", - "ai": "catalog:", - "hono": "catalog:", - "zod": "catalog:" - } -} diff --git a/cloud/function/src/auth.ts b/cloud/function/src/auth.ts deleted file mode 100644 index bbea4154028..00000000000 --- a/cloud/function/src/auth.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Resource } from "sst" -import { z } from "zod" -import { issuer } from "@openauthjs/openauth" -import { createSubjects } from "@openauthjs/openauth/subject" -import { GithubProvider } from "@openauthjs/openauth/provider/github" -import { GoogleOidcProvider } from "@openauthjs/openauth/provider/google" -import { CloudflareStorage } from "@openauthjs/openauth/storage/cloudflare" -import { Account } from "@opencode/cloud-core/account.js" -import { Workspace } from "@opencode/cloud-core/workspace.js" -import { Actor } from "@opencode/cloud-core/actor.js" - -type Env = { - AuthStorage: KVNamespace -} - -export const subjects = createSubjects({ - account: z.object({ - accountID: z.string(), - email: z.string(), - }), - user: z.object({ - userID: z.string(), - workspaceID: z.string(), - }), -}) - -export default { - async fetch(request: Request, env: Env, ctx: ExecutionContext) { - return issuer({ - providers: { - github: GithubProvider({ - clientID: Resource.GITHUB_CLIENT_ID_CONSOLE.value, - clientSecret: Resource.GITHUB_CLIENT_SECRET_CONSOLE.value, - scopes: ["read:user", "user:email"], - }), - google: GoogleOidcProvider({ - clientID: Resource.GOOGLE_CLIENT_ID.value, - scopes: ["openid", "email"], - }), - // email: CodeProvider({ - // async request(req, state, form, error) { - // console.log(state) - // const params = new URLSearchParams() - // if (error) { - // params.set("error", error.type) - // } - // if (state.type === "start") { - // return Response.redirect(process.env.AUTH_FRONTEND_URL + "/auth/email?" + params.toString(), 302) - // } - // - // if (state.type === "code") { - // return Response.redirect(process.env.AUTH_FRONTEND_URL + "/auth/code?" + params.toString(), 302) - // } - // - // return new Response("ok") - // }, - // async sendCode(claims, code) { - // const email = z.string().email().parse(claims.email) - // const cmd = new SendEmailCommand({ - // Destination: { - // ToAddresses: [email], - // }, - // FromEmailAddress: `SST `, - // Content: { - // Simple: { - // Body: { - // Html: { - // Data: `Your pin code is ${code}`, - // }, - // Text: { - // Data: `Your pin code is ${code}`, - // }, - // }, - // Subject: { - // Data: "SST Console Pin Code: " + code, - // }, - // }, - // }, - // }) - // await ses.send(cmd) - // }, - // }), - }, - storage: CloudflareStorage({ - namespace: env.AuthStorage, - }), - subjects, - async success(ctx, response) { - console.log(response) - - let email: string | undefined - - if (response.provider === "github") { - const userResponse = await fetch("https://api.github.com/user", { - headers: { - Authorization: `Bearer ${response.tokenset.access}`, - "User-Agent": "opencode", - Accept: "application/vnd.github+json", - }, - }) - const user = (await userResponse.json()) as { email: string } - email = user.email - } else if (response.provider === "google") { - if (!response.id.email_verified) throw new Error("Google email not verified") - email = response.id.email as string - } - //if (response.provider === "email") { - // email = response.claims.email - //} - else throw new Error("Unsupported provider") - - if (!email) throw new Error("No email found") - - let accountID = await Account.fromEmail(email).then((x) => x?.id) - if (!accountID) { - console.log("creating account for", email) - accountID = await Account.create({ - email: email!, - }) - } - await Actor.provide("account", { accountID, email }, async () => { - const workspaces = await Account.workspaces() - if (workspaces.length === 0) { - await Workspace.create() - } - }) - return ctx.subject("account", accountID, { accountID, email }) - }, - }).fetch(request, env, ctx) - }, -} diff --git a/cloud/function/src/gateway.ts b/cloud/function/src/gateway.ts deleted file mode 100644 index 2f498276f05..00000000000 --- a/cloud/function/src/gateway.ts +++ /dev/null @@ -1,909 +0,0 @@ -import { z } from "zod" -import { Hono, MiddlewareHandler } from "hono" -import { cors } from "hono/cors" -import { HTTPException } from "hono/http-exception" -import { zValidator } from "@hono/zod-validator" -import { Resource } from "sst" -import { type ProviderMetadata, type LanguageModelUsage, generateText, streamText } from "ai" -import { createAnthropic } from "@ai-sdk/anthropic" -import { createOpenAI } from "@ai-sdk/openai" -import { createOpenAICompatible } from "@ai-sdk/openai-compatible" -import type { LanguageModelV2Prompt } from "@ai-sdk/provider" -import { type ChatCompletionCreateParamsBase } from "openai/resources/chat/completions" -import { Actor } from "@opencode/cloud-core/actor.js" -import { and, Database, eq, sql } from "@opencode/cloud-core/drizzle/index.js" -import { UserTable } from "@opencode/cloud-core/schema/user.sql.js" -import { KeyTable } from "@opencode/cloud-core/schema/key.sql.js" -import { createClient } from "@openauthjs/openauth/client" -import { Log } from "@opencode/cloud-core/util/log.js" -import { Billing } from "@opencode/cloud-core/billing.js" -import { Workspace } from "@opencode/cloud-core/workspace.js" -import { BillingTable, PaymentTable, UsageTable } from "@opencode/cloud-core/schema/billing.sql.js" -import { centsToMicroCents } from "@opencode/cloud-core/util/price.js" -import { Identifier } from "../../core/src/identifier" - -type Env = {} - -let _client: ReturnType -const client = () => { - if (_client) return _client - _client = createClient({ - clientID: "api", - issuer: Resource.AUTH_API_URL.value, - }) - return _client -} - -const SUPPORTED_MODELS = { - "anthropic/claude-sonnet-4": { - input: 0.0000015, - output: 0.000006, - reasoning: 0.0000015, - cacheRead: 0.0000001, - cacheWrite: 0.0000001, - model: () => - createAnthropic({ - apiKey: Resource.ANTHROPIC_API_KEY.value, - })("claude-sonnet-4-20250514"), - }, - "openai/gpt-4.1": { - input: 0.0000015, - output: 0.000006, - reasoning: 0.0000015, - cacheRead: 0.0000001, - cacheWrite: 0.0000001, - model: () => - createOpenAI({ - apiKey: Resource.OPENAI_API_KEY.value, - })("gpt-4.1"), - }, - "zhipuai/glm-4.5-flash": { - input: 0, - output: 0, - reasoning: 0, - cacheRead: 0, - cacheWrite: 0, - model: () => - createOpenAICompatible({ - name: "Zhipu AI", - baseURL: "https://api.z.ai/api/paas/v4", - apiKey: Resource.ZHIPU_API_KEY.value, - })("glm-4.5-flash"), - }, -} - -const log = Log.create({ - namespace: "api", -}) - -const GatewayAuth: MiddlewareHandler = async (c, next) => { - const authHeader = c.req.header("authorization") - - if (!authHeader || !authHeader.startsWith("Bearer ")) { - return c.json( - { - error: { - message: "Missing API key.", - type: "invalid_request_error", - param: null, - code: "unauthorized", - }, - }, - 401, - ) - } - - const apiKey = authHeader.split(" ")[1] - - // Check against KeyTable - const keyRecord = await Database.use((tx) => - tx - .select({ - id: KeyTable.id, - workspaceID: KeyTable.workspaceID, - }) - .from(KeyTable) - .where(eq(KeyTable.key, apiKey)) - .then((rows) => rows[0]), - ) - - if (!keyRecord) { - return c.json( - { - error: { - message: "Invalid API key.", - type: "invalid_request_error", - param: null, - code: "unauthorized", - }, - }, - 401, - ) - } - - c.set("keyRecord", keyRecord) - await next() -} - -const RestAuth: MiddlewareHandler = async (c, next) => { - const authorization = c.req.header("authorization") - if (!authorization) { - return Actor.provide("public", {}, next) - } - const token = authorization.split(" ")[1] - if (!token) - throw new HTTPException(403, { - message: "Bearer token is required.", - }) - - const verified = await client().verify(token) - if (verified.err) { - throw new HTTPException(403, { - message: "Invalid token.", - }) - } - let subject = verified.subject as Actor.Info - if (subject.type === "account") { - const workspaceID = c.req.header("x-opencode-workspace") - const email = subject.properties.email - if (workspaceID) { - const user = await Database.use((tx) => - tx - .select({ - id: UserTable.id, - workspaceID: UserTable.workspaceID, - email: UserTable.email, - }) - .from(UserTable) - .where(and(eq(UserTable.email, email), eq(UserTable.workspaceID, workspaceID))) - .then((rows) => rows[0]), - ) - if (!user) - throw new HTTPException(403, { - message: "You do not have access to this workspace.", - }) - subject = { - type: "user", - properties: { - userID: user.id, - workspaceID: workspaceID, - email: user.email, - }, - } - } - } - await Actor.provide(subject.type, subject.properties, next) -} - -const app = new Hono<{ Bindings: Env; Variables: { keyRecord?: { id: string; workspaceID: string } } }>() - .get("/", (c) => c.text("Hello, world!")) - .post("/v1/chat/completions", GatewayAuth, async (c) => { - const keyRecord = c.get("keyRecord")! - - return await Actor.provide("system", { workspaceID: keyRecord.workspaceID }, async () => { - try { - // Check balance - const customer = await Billing.get() - if (customer.balance <= 0) { - return c.json( - { - error: { - message: "Insufficient balance", - type: "insufficient_quota", - param: null, - code: "insufficient_quota", - }, - }, - 401, - ) - } - - const body = await c.req.json() - const model = SUPPORTED_MODELS[body.model as keyof typeof SUPPORTED_MODELS]?.model() - if (!model) throw new Error(`Unsupported model: ${body.model}`) - - const requestBody = transformOpenAIRequestToAiSDK() - - return body.stream ? await handleStream() : await handleGenerate() - - async function handleStream() { - const result = await model.doStream({ - ...requestBody, - }) - - const encoder = new TextEncoder() - const stream = new ReadableStream({ - async start(controller) { - const id = `chatcmpl-${Date.now()}` - const created = Math.floor(Date.now() / 1000) - - try { - for await (const chunk of result.stream) { - console.log("!!! CHUNK !!! : " + chunk.type) - switch (chunk.type) { - case "text-delta": { - const data = { - id, - object: "chat.completion.chunk", - created, - model: body.model, - choices: [ - { - index: 0, - delta: { - content: chunk.delta, - }, - finish_reason: null, - }, - ], - } - controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) - break - } - - case "reasoning-delta": { - const data = { - id, - object: "chat.completion.chunk", - created, - model: body.model, - choices: [ - { - index: 0, - delta: { - reasoning_content: chunk.delta, - }, - finish_reason: null, - }, - ], - } - controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) - break - } - - case "tool-call": { - const data = { - id, - object: "chat.completion.chunk", - created, - model: body.model, - choices: [ - { - index: 0, - delta: { - tool_calls: [ - { - index: 0, - id: chunk.toolCallId, - type: "function", - function: { - name: chunk.toolName, - arguments: chunk.input, - }, - }, - ], - }, - finish_reason: null, - }, - ], - } - controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) - break - } - - case "error": { - const data = { - id, - object: "chat.completion.chunk", - created, - model: body.model, - choices: [ - { - index: 0, - delta: {}, - finish_reason: "stop", - }, - ], - error: { - message: typeof chunk.error === "string" ? chunk.error : chunk.error, - type: "server_error", - }, - } - controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) - controller.enqueue(encoder.encode("data: [DONE]\n\n")) - controller.close() - break - } - - case "finish": { - const data = { - id, - object: "chat.completion.chunk", - created, - model: body.model, - choices: [ - { - index: 0, - delta: {}, - finish_reason: - { - stop: "stop", - length: "length", - "content-filter": "content_filter", - "tool-calls": "tool_calls", - error: "stop", - other: "stop", - unknown: "stop", - }[chunk.finishReason] || "stop", - }, - ], - usage: { - prompt_tokens: chunk.usage.inputTokens, - completion_tokens: chunk.usage.outputTokens, - total_tokens: chunk.usage.totalTokens, - completion_tokens_details: { - reasoning_tokens: chunk.usage.reasoningTokens, - }, - prompt_tokens_details: { - cached_tokens: chunk.usage.cachedInputTokens, - }, - }, - } - await trackUsage(body.model, chunk.usage, chunk.providerMetadata) - controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) - controller.enqueue(encoder.encode("data: [DONE]\n\n")) - controller.close() - break - } - - //case "stream-start": - //case "response-metadata": - case "text-start": - case "text-end": - case "reasoning-start": - case "reasoning-end": - case "tool-input-start": - case "tool-input-delta": - case "tool-input-end": - case "raw": - default: - // Log unknown chunk types for debugging - console.warn(`Unknown chunk type: ${(chunk as any).type}`) - break - } - } - } catch (error) { - controller.error(error) - } - }, - }) - - return new Response(stream, { - headers: { - "Content-Type": "text/plain; charset=utf-8", - "Cache-Control": "no-cache", - Connection: "keep-alive", - }, - }) - } - - async function handleGenerate() { - const response = await model.doGenerate({ - ...requestBody, - }) - await trackUsage(body.model, response.usage, response.providerMetadata) - return c.json({ - id: `chatcmpl-${Date.now()}`, - object: "chat.completion" as const, - created: Math.floor(Date.now() / 1000), - model: body.model, - choices: [ - { - index: 0, - message: { - role: "assistant" as const, - content: response.content?.find((c) => c.type === "text")?.text ?? "", - reasoning_content: response.content?.find((c) => c.type === "reasoning")?.text, - tool_calls: response.content - ?.filter((c) => c.type === "tool-call") - .map((toolCall) => ({ - id: toolCall.toolCallId, - type: "function" as const, - function: { - name: toolCall.toolName, - arguments: toolCall.input, - }, - })), - }, - finish_reason: - ( - { - stop: "stop", - length: "length", - "content-filter": "content_filter", - "tool-calls": "tool_calls", - error: "stop", - other: "stop", - unknown: "stop", - } as const - )[response.finishReason] || "stop", - }, - ], - usage: { - prompt_tokens: response.usage?.inputTokens, - completion_tokens: response.usage?.outputTokens, - total_tokens: response.usage?.totalTokens, - completion_tokens_details: { - reasoning_tokens: response.usage?.reasoningTokens, - }, - prompt_tokens_details: { - cached_tokens: response.usage?.cachedInputTokens, - }, - }, - }) - } - - function transformOpenAIRequestToAiSDK() { - const prompt = transformMessages() - const tools = transformTools() - - return { - prompt, - maxOutputTokens: body.max_tokens ?? body.max_completion_tokens ?? undefined, - temperature: body.temperature ?? undefined, - topP: body.top_p ?? undefined, - frequencyPenalty: body.frequency_penalty ?? undefined, - presencePenalty: body.presence_penalty ?? undefined, - providerOptions: body.reasoning_effort - ? { - anthropic: { - reasoningEffort: body.reasoning_effort, - }, - } - : undefined, - stopSequences: (typeof body.stop === "string" ? [body.stop] : body.stop) ?? undefined, - responseFormat: (() => { - if (!body.response_format) return { type: "text" as const } - if (body.response_format.type === "json_schema") - return { - type: "json" as const, - schema: body.response_format.json_schema.schema, - name: body.response_format.json_schema.name, - description: body.response_format.json_schema.description, - } - if (body.response_format.type === "json_object") return { type: "json" as const } - throw new Error("Unsupported response format") - })(), - seed: body.seed ?? undefined, - tools: tools.tools, - toolChoice: tools.toolChoice, - } - - function transformTools() { - const { tools, tool_choice } = body - - if (!tools || tools.length === 0) { - return { tools: undefined, toolChoice: undefined } - } - - const aiSdkTools = tools.map((tool) => { - return { - type: tool.type, - name: tool.function.name, - description: tool.function.description, - inputSchema: tool.function.parameters!, - } - }) - - let aiSdkToolChoice - if (tool_choice == null) { - aiSdkToolChoice = undefined - } else if (tool_choice === "auto") { - aiSdkToolChoice = { type: "auto" as const } - } else if (tool_choice === "none") { - aiSdkToolChoice = { type: "none" as const } - } else if (tool_choice === "required") { - aiSdkToolChoice = { type: "required" as const } - } else if (tool_choice.type === "function") { - aiSdkToolChoice = { - type: "tool" as const, - toolName: tool_choice.function.name, - } - } - - return { tools: aiSdkTools, toolChoice: aiSdkToolChoice } - } - - function transformMessages() { - const { messages } = body - const prompt: LanguageModelV2Prompt = [] - - for (const message of messages) { - switch (message.role) { - case "system": { - prompt.push({ - role: "system", - content: message.content as string, - }) - break - } - - case "user": { - if (typeof message.content === "string") { - prompt.push({ - role: "user", - content: [{ type: "text", text: message.content }], - }) - } else { - const content = message.content.map((part) => { - switch (part.type) { - case "text": - return { type: "text" as const, text: part.text } - case "image_url": - return { - type: "file" as const, - mediaType: "image/jpeg" as const, - data: part.image_url.url, - } - default: - throw new Error(`Unsupported content part type: ${(part as any).type}`) - } - }) - prompt.push({ - role: "user", - content, - }) - } - break - } - - case "assistant": { - const content: Array< - | { type: "text"; text: string } - | { - type: "tool-call" - toolCallId: string - toolName: string - input: any - } - > = [] - - if (message.content) { - content.push({ - type: "text", - text: message.content as string, - }) - } - - if (message.tool_calls) { - for (const toolCall of message.tool_calls) { - content.push({ - type: "tool-call", - toolCallId: toolCall.id, - toolName: toolCall.function.name, - input: JSON.parse(toolCall.function.arguments), - }) - } - } - - prompt.push({ - role: "assistant", - content, - }) - break - } - - case "tool": { - prompt.push({ - role: "tool", - content: [ - { - type: "tool-result", - toolName: "placeholder", - toolCallId: message.tool_call_id, - output: { - type: "text", - value: message.content as string, - }, - }, - ], - }) - break - } - - default: { - throw new Error(`Unsupported message role: ${message.role}`) - } - } - } - - return prompt - } - } - - async function trackUsage(model: string, usage: LanguageModelUsage, providerMetadata?: ProviderMetadata) { - const modelData = SUPPORTED_MODELS[model as keyof typeof SUPPORTED_MODELS] - if (!modelData) throw new Error(`Unsupported model: ${model}`) - - const inputTokens = usage.inputTokens ?? 0 - const outputTokens = usage.outputTokens ?? 0 - const reasoningTokens = usage.reasoningTokens ?? 0 - const cacheReadTokens = usage.cachedInputTokens ?? 0 - const cacheWriteTokens = - providerMetadata?.["anthropic"]?.["cacheCreationInputTokens"] ?? - // @ts-expect-error - providerMetadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ?? - 0 - - const inputCost = modelData.input * inputTokens - const outputCost = modelData.output * outputTokens - const reasoningCost = modelData.reasoning * reasoningTokens - const cacheReadCost = modelData.cacheRead * cacheReadTokens - const cacheWriteCost = modelData.cacheWrite * cacheWriteTokens - const costInCents = (inputCost + outputCost + reasoningCost + cacheReadCost + cacheWriteCost) * 100 - - await Billing.consume({ - model, - inputTokens, - outputTokens, - reasoningTokens, - cacheReadTokens, - cacheWriteTokens, - costInCents, - }) - - await Database.use((tx) => - tx - .update(KeyTable) - .set({ timeUsed: sql`now()` }) - .where(eq(KeyTable.id, keyRecord.id)), - ) - } - } catch (error: any) { - return c.json({ error: { message: error.message } }, 500) - } - }) - }) - .use("/*", cors()) - .use(RestAuth) - .get("/rest/account", async (c) => { - const account = Actor.assert("account") - let workspaces = await Workspace.list() - if (workspaces.length === 0) { - await Workspace.create() - workspaces = await Workspace.list() - } - return c.json({ - id: account.properties.accountID, - email: account.properties.email, - workspaces, - }) - }) - .get("/billing/info", async (c) => { - const billing = await Billing.get() - const payments = await Database.use((tx) => - tx - .select() - .from(PaymentTable) - .where(eq(PaymentTable.workspaceID, Actor.workspace())) - .orderBy(sql`${PaymentTable.timeCreated} DESC`) - .limit(100), - ) - const usage = await Database.use((tx) => - tx - .select() - .from(UsageTable) - .where(eq(UsageTable.workspaceID, Actor.workspace())) - .orderBy(sql`${UsageTable.timeCreated} DESC`) - .limit(100), - ) - return c.json({ billing, payments, usage }) - }) - .post( - "/billing/checkout", - zValidator( - "json", - z.custom<{ - success_url: string - cancel_url: string - }>(), - ), - async (c) => { - const account = Actor.assert("user") - - const body = await c.req.json() - - const customer = await Billing.get() - const session = await Billing.stripe().checkout.sessions.create({ - mode: "payment", - line_items: [ - { - price_data: { - currency: "usd", - product_data: { - name: "opencode credits", - }, - unit_amount: 2000, // $20 minimum - }, - quantity: 1, - }, - ], - payment_intent_data: { - setup_future_usage: "on_session", - }, - ...(customer.customerID - ? { customer: customer.customerID } - : { - customer_email: account.properties.email, - customer_creation: "always", - }), - metadata: { - workspaceID: Actor.workspace(), - }, - currency: "usd", - payment_method_types: ["card"], - success_url: body.success_url, - cancel_url: body.cancel_url, - }) - - return c.json({ - url: session.url, - }) - }, - ) - .post("/billing/portal", async (c) => { - const body = await c.req.json() - - const customer = await Billing.get() - if (!customer?.customerID) { - throw new Error("No stripe customer ID") - } - - const session = await Billing.stripe().billingPortal.sessions.create({ - customer: customer.customerID, - return_url: body.return_url, - }) - - return c.json({ - url: session.url, - }) - }) - .post("/stripe/webhook", async (c) => { - const body = await Billing.stripe().webhooks.constructEventAsync( - await c.req.text(), - c.req.header("stripe-signature")!, - Resource.STRIPE_WEBHOOK_SECRET.value, - ) - - console.log(body.type, JSON.stringify(body, null, 2)) - if (body.type === "checkout.session.completed") { - const workspaceID = body.data.object.metadata?.workspaceID - const customerID = body.data.object.customer as string - const paymentID = body.data.object.payment_intent as string - const amount = body.data.object.amount_total - - if (!workspaceID) throw new Error("Workspace ID not found") - if (!customerID) throw new Error("Customer ID not found") - if (!amount) throw new Error("Amount not found") - if (!paymentID) throw new Error("Payment ID not found") - - await Actor.provide("system", { workspaceID }, async () => { - const customer = await Billing.get() - if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch") - - // set customer metadata - if (!customer?.customerID) { - await Billing.stripe().customers.update(customerID, { - metadata: { - workspaceID, - }, - }) - } - - // get payment method for the payment intent - const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, { - expand: ["payment_method"], - }) - const paymentMethod = paymentIntent.payment_method - if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded") - - await Database.transaction(async (tx) => { - await tx - .update(BillingTable) - .set({ - balance: sql`${BillingTable.balance} + ${centsToMicroCents(amount)}`, - customerID, - paymentMethodID: paymentMethod.id, - paymentMethodLast4: paymentMethod.card!.last4, - }) - .where(eq(BillingTable.workspaceID, workspaceID)) - await tx.insert(PaymentTable).values({ - workspaceID, - id: Identifier.create("payment"), - amount: centsToMicroCents(amount), - paymentID, - customerID, - }) - }) - }) - } - - console.log("finished handling") - - return c.json("ok", 200) - }) - .get("/keys", async (c) => { - const user = Actor.assert("user") - - const keys = await Database.use((tx) => - tx - .select({ - id: KeyTable.id, - name: KeyTable.name, - key: KeyTable.key, - userID: KeyTable.userID, - timeCreated: KeyTable.timeCreated, - timeUsed: KeyTable.timeUsed, - }) - .from(KeyTable) - .where(eq(KeyTable.workspaceID, user.properties.workspaceID)) - .orderBy(sql`${KeyTable.timeCreated} DESC`), - ) - - return c.json({ keys }) - }) - .post("/keys", zValidator("json", z.object({ name: z.string().min(1).max(255) })), async (c) => { - const user = Actor.assert("user") - const { name } = c.req.valid("json") - - // Generate secret key: sk- + 64 random characters (upper, lower, numbers) - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - let randomPart = "" - for (let i = 0; i < 64; i++) { - randomPart += chars.charAt(Math.floor(Math.random() * chars.length)) - } - const secretKey = `sk-${randomPart}` - - const keyRecord = await Database.use((tx) => - tx - .insert(KeyTable) - .values({ - id: Identifier.create("key"), - workspaceID: user.properties.workspaceID, - userID: user.properties.userID, - name, - key: secretKey, - timeUsed: null, - }) - .returning(), - ) - - return c.json({ - key: secretKey, - id: keyRecord[0].id, - name: keyRecord[0].name, - created: keyRecord[0].timeCreated, - }) - }) - .delete("/keys/:id", async (c) => { - const user = Actor.assert("user") - const keyId = c.req.param("id") - - const result = await Database.use((tx) => - tx - .delete(KeyTable) - .where(and(eq(KeyTable.id, keyId), eq(KeyTable.workspaceID, user.properties.workspaceID))) - .returning({ id: KeyTable.id }), - ) - - if (result.length === 0) { - return c.json({ error: "Key not found" }, 404) - } - - return c.json({ success: true, id: result[0].id }) - }) - .all("*", (c) => c.text("Not Found")) - -export type ApiType = typeof app - -export default app diff --git a/cloud/function/sst-env.d.ts b/cloud/function/sst-env.d.ts deleted file mode 100644 index f60ec81a0fb..00000000000 --- a/cloud/function/sst-env.d.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* This file is auto-generated by SST. Do not edit. */ -/* tslint:disable */ -/* eslint-disable */ -/* deno-fmt-ignore-file */ - -import "sst" -declare module "sst" { - export interface Resource { - "ANTHROPIC_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string - } - "DATABASE_PASSWORD": { - "type": "sst.sst.Secret" - "value": string - } - "DATABASE_USERNAME": { - "type": "sst.sst.Secret" - "value": string - } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string - } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "OPENAI_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string - } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string - } - "ZHIPU_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - } -} -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; -declare module "sst" { - export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "GatewayApi": cloudflare.Service - } -} - -import "sst" -export {} \ No newline at end of file diff --git a/cloud/function/tsconfig.json b/cloud/function/tsconfig.json deleted file mode 100644 index 0faf16aab7a..00000000000 --- a/cloud/function/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@tsconfig/node22/tsconfig.json", - "compilerOptions": { - "module": "ESNext", - "moduleResolution": "bundler", - "types": ["@cloudflare/workers-types", "node"] - } -} diff --git a/cloud/web/.gitignore b/cloud/web/.gitignore deleted file mode 100644 index 76add878f8d..00000000000 --- a/cloud/web/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/cloud/web/index.html b/cloud/web/index.html deleted file mode 100644 index 55c54c1f133..00000000000 --- a/cloud/web/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - OpenControl - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - diff --git a/cloud/web/npm-debug.log b/cloud/web/npm-debug.log deleted file mode 100644 index 07b0649fe17..00000000000 --- a/cloud/web/npm-debug.log +++ /dev/null @@ -1,29 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ -1 verbose cli '/usr/local/bin/node', -1 verbose cli '/Users/frank/Sites/opencode/node_modules/.bin/npm', -1 verbose cli 'run', -1 verbose cli 'dev' -1 verbose cli ] -2 info using npm@2.15.12 -3 info using node@v20.18.1 -4 verbose stack Error: Invalid name: "@opencode/cloud/web" -4 verbose stack at ensureValidName (/Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/fixer.js:336:15) -4 verbose stack at Object.fixNameField (/Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/fixer.js:215:5) -4 verbose stack at /Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/normalize.js:32:38 -4 verbose stack at Array.forEach () -4 verbose stack at normalize (/Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/normalize.js:31:15) -4 verbose stack at final (/Users/frank/Sites/opencode/node_modules/npm/node_modules/read-package-json/read-json.js:349:5) -4 verbose stack at then (/Users/frank/Sites/opencode/node_modules/npm/node_modules/read-package-json/read-json.js:124:5) -4 verbose stack at ReadFileContext. (/Users/frank/Sites/opencode/node_modules/npm/node_modules/read-package-json/read-json.js:295:20) -4 verbose stack at ReadFileContext.callback (/Users/frank/Sites/opencode/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16) -4 verbose stack at FSReqCallback.readFileAfterOpen [as oncomplete] (node:fs:299:13) -5 verbose cwd /Users/frank/Sites/opencode/cloud/web -6 error Darwin 24.5.0 -7 error argv "/usr/local/bin/node" "/Users/frank/Sites/opencode/node_modules/.bin/npm" "run" "dev" -8 error node v20.18.1 -9 error npm v2.15.12 -10 error Invalid name: "@opencode/cloud/web" -11 error If you need help, you may report this error at: -11 error -12 verbose exit [ 1, true ] diff --git a/cloud/web/package.json b/cloud/web/package.json deleted file mode 100644 index 9758127978b..00000000000 --- a/cloud/web/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@opencode/cloud-web", - "version": "0.5.13", - "private": true, - "description": "", - "type": "module", - "scripts": { - "start": "vite", - "dev": "vite", - "build": "bun build:server && bun build:client", - "build:client": "vite build --outDir dist/client", - "build:server": "vite build --ssr src/entry-server.tsx --outDir dist/server", - "serve": "vite preview", - "sst:dev": "bun sst shell --target Console -- bun dev" - }, - "license": "MIT", - "devDependencies": { - "typescript": "catalog:", - "vite": "6.2.2", - "vite-plugin-pages": "0.32.5", - "vite-plugin-solid": "2.11.6" - }, - "dependencies": { - "@kobalte/core": "0.13.9", - "@openauthjs/solid": "0.0.0-20250322224806", - "@solid-primitives/storage": "4.3.1", - "@solidjs/meta": "0.29.4", - "@solidjs/router": "0.15.3", - "solid-js": "1.9.5", - "solid-list": "0.3.0" - } -} diff --git a/cloud/web/public/favicon-dark.svg b/cloud/web/public/favicon-dark.svg deleted file mode 100644 index 9b707ea494b..00000000000 --- a/cloud/web/public/favicon-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/cloud/web/public/favicon.ico b/cloud/web/public/favicon.ico deleted file mode 100644 index 0ed3bf15e76..00000000000 Binary files a/cloud/web/public/favicon.ico and /dev/null differ diff --git a/cloud/web/public/favicon.svg b/cloud/web/public/favicon.svg deleted file mode 100644 index 5e7cf124fcb..00000000000 --- a/cloud/web/public/favicon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/cloud/web/public/social-share.png b/cloud/web/public/social-share.png deleted file mode 100644 index 72d36a9722a..00000000000 Binary files a/cloud/web/public/social-share.png and /dev/null differ diff --git a/cloud/web/scripts/render.mjs b/cloud/web/scripts/render.mjs deleted file mode 100644 index 5ccb35ff128..00000000000 --- a/cloud/web/scripts/render.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import fs from "fs" -import path from "path" -import { generateHydrationScript, getAssets } from "solid-js/web" - -const dist = import.meta.resolve("../dist").replace("file://", "") -const serverEntry = await import("../dist/server/entry-server.js") -const template = fs.readFileSync(path.join(dist, "client/index.html"), "utf-8") -fs.writeFileSync(path.join(dist, "client/fallback.html"), template) - -const routes = ["/", "/foo"] -for (const route of routes) { - const { app } = serverEntry.render({ url: route }) - const html = template - .replace("", app) - .replace("", generateHydrationScript()) - .replace("", getAssets()) - const filePath = dist + `/client${route === "/" ? "/index" : route}.html` - fs.mkdirSync(path.dirname(filePath), { - recursive: true, - }) - fs.writeFileSync(filePath, html) - - console.log(`Pre-rendered: ${filePath}`) -} diff --git a/cloud/web/src/app.tsx b/cloud/web/src/app.tsx deleted file mode 100644 index aae71ddded2..00000000000 --- a/cloud/web/src/app.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/// - -import { Router } from "@solidjs/router" -import routes from "~solid-pages" -import "./ui/style/index.css" -import { MetaProvider } from "@solidjs/meta" -import { AccountProvider } from "./components/context-account" -import { DialogProvider } from "./ui/context-dialog" -import { DialogString } from "./ui/dialog-string" -import { DialogSelect } from "./ui/dialog-select" -import { ThemeProvider } from "./components/context-theme" -import { Suspense } from "solid-js" -import { OpenAuthProvider } from "./components/context-openauth" - -export function App(props: { url?: string }) { - return ( - - - - - - - - - { - return <>{props.children} - }} - /> - - - - - - - ) -} diff --git a/cloud/web/src/assets/screenshot.png b/cloud/web/src/assets/screenshot.png deleted file mode 100644 index 5b6ad2ec68c..00000000000 Binary files a/cloud/web/src/assets/screenshot.png and /dev/null differ diff --git a/cloud/web/src/components/context-account.tsx b/cloud/web/src/components/context-account.tsx deleted file mode 100644 index e6aabafd3ec..00000000000 --- a/cloud/web/src/components/context-account.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { createContext, createEffect, ParentProps, Suspense, useContext } from "solid-js" -import { makePersisted } from "@solid-primitives/storage" -import { createStore } from "solid-js/store" -import { useOpenAuth } from "./context-openauth" -import { createAsync } from "@solidjs/router" -import { isServer } from "solid-js/web" - -type Storage = { - accounts: Record< - string, - { - id: string - email: string - workspaces: { - id: string - name: string - slug: string - }[] - } - > -} - -const context = createContext>() - -function init() { - const auth = useOpenAuth() - const [store, setStore] = makePersisted( - createStore({ - accounts: {}, - }), - { - name: "opencontrol.account", - }, - ) - - async function refresh(id: string) { - return fetch(import.meta.env.VITE_API_URL + "/rest/account", { - headers: { - authorization: `Bearer ${await auth.access(id)}`, - }, - }) - .then((val) => val.json()) - .then((val) => setStore("accounts", id, val as any)) - } - - createEffect((previous: string[]) => { - if (Object.keys(auth.all).length === 0) { - return [] - } - for (const item of Object.values(auth.all)) { - if (previous.includes(item.id)) continue - refresh(item.id) - } - return Object.keys(auth.all) - }, [] as string[]) - - const result = { - get all() { - return Object.keys(auth.all) - .map((id) => store.accounts[id]) - .filter(Boolean) - }, - get current() { - if (!auth.subject) return undefined - return store.accounts[auth.subject.id] - }, - refresh, - get ready() { - return Object.keys(auth.all).length === result.all.length - }, - } - - return result -} - -export function AccountProvider(props: ParentProps) { - const ctx = init() - const resource = createAsync(async () => { - await new Promise((resolve) => { - if (isServer) return resolve() - createEffect(() => { - if (ctx.ready) resolve() - }) - }) - return null - }) - return ( - - {resource()} - {props.children} - - ) -} - -export function useAccount() { - const result = useContext(context) - if (!result) throw new Error("no account context") - return result -} diff --git a/cloud/web/src/components/context-openauth.tsx b/cloud/web/src/components/context-openauth.tsx deleted file mode 100644 index bd6a45dd1d2..00000000000 --- a/cloud/web/src/components/context-openauth.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { createClient } from "@openauthjs/openauth/client" -import { makePersisted } from "@solid-primitives/storage" -import { createAsync } from "@solidjs/router" -import { - batch, - createContext, - createEffect, - createResource, - createSignal, - onMount, - ParentProps, - Show, - Suspense, - useContext, -} from "solid-js" -import { createStore, produce } from "solid-js/store" -import { isServer } from "solid-js/web" - -interface Storage { - subjects: Record - current?: string -} - -interface Context { - all: Record - subject?: SubjectInfo - switch(id: string): void - logout(id: string): void - access(id?: string): Promise - authorize(opts?: AuthorizeOptions): void -} - -export interface AuthorizeOptions { - redirectPath?: string - provider?: string -} - -interface SubjectInfo { - id: string - refresh: string -} - -interface AuthContextOpts { - issuer: string - clientID: string -} - -const context = createContext() - -export function OpenAuthProvider(props: ParentProps) { - const client = createClient({ - issuer: props.issuer, - clientID: props.clientID, - }) - const [storage, setStorage] = makePersisted( - createStore({ - subjects: {}, - }), - { - name: `${props.issuer}.auth`, - }, - ) - - const resource = createAsync(async () => { - if (isServer) return true - const hash = new URLSearchParams(window.location.search.substring(1)) - const code = hash.get("code") - const state = hash.get("state") - if (code && state) { - const oldState = sessionStorage.getItem("openauth.state") - const verifier = sessionStorage.getItem("openauth.verifier") - const redirect = sessionStorage.getItem("openauth.redirect") - if (redirect && verifier && oldState === state) { - const result = await client.exchange(code, redirect, verifier) - if (!result.err) { - const id = result.tokens.refresh.split(":").slice(0, -1).join(":") - batch(() => { - setStorage("subjects", id, { - id: id, - refresh: result.tokens.refresh, - }) - setStorage("current", id) - }) - } - } - } - return true - }) - - async function authorize(opts?: AuthorizeOptions) { - const redirect = new URL(window.location.origin + (opts?.redirectPath ?? "/")).toString() - const authorize = await client.authorize(redirect, "code", { - pkce: true, - provider: opts?.provider, - }) - sessionStorage.setItem("openauth.state", authorize.challenge.state) - sessionStorage.setItem("openauth.redirect", redirect) - if (authorize.challenge.verifier) sessionStorage.setItem("openauth.verifier", authorize.challenge.verifier) - window.location.href = authorize.url - } - - const accessCache = new Map() - const pendingRequests = new Map>() - async function access(id: string) { - const pending = pendingRequests.get(id) - if (pending) return pending - const promise = (async () => { - const existing = accessCache.get(id) - const subject = storage.subjects[id] - const access = await client.refresh(subject.refresh, { - access: existing, - }) - if (access.err) { - pendingRequests.delete(id) - ctx.logout(id) - return - } - if (access.tokens) { - setStorage("subjects", id, "refresh", access.tokens.refresh) - accessCache.set(id, access.tokens.access) - } - pendingRequests.delete(id) - return access.tokens?.access || existing! - })() - pendingRequests.set(id, promise) - return promise - } - - const ctx: Context = { - get all() { - return storage.subjects - }, - get subject() { - if (!storage.current) return - return storage.subjects[storage.current!] - }, - switch(id: string) { - if (!storage.subjects[id]) return - setStorage("current", id) - }, - authorize, - logout(id: string) { - if (!storage.subjects[id]) return - setStorage( - produce((s) => { - delete s.subjects[id] - if (s.current === id) s.current = Object.keys(s.subjects)[0] - }), - ) - }, - async access(id?: string) { - id = id || storage.current - if (!id) return - return access(id || storage.current!) - }, - } - - createEffect(() => { - if (!resource()) return - if (storage.current) return - const [first] = Object.keys(storage.subjects) - if (first) { - setStorage("current", first) - return - } - }) - - return ( - <> - {resource()} - {props.children} - - ) -} - -export function useOpenAuth() { - const result = useContext(context) - if (!result) throw new Error("no auth context") - return result -} diff --git a/cloud/web/src/components/context-theme.tsx b/cloud/web/src/components/context-theme.tsx deleted file mode 100644 index 7800aeca039..00000000000 --- a/cloud/web/src/components/context-theme.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { createStore } from "solid-js/store" -import { makePersisted } from "@solid-primitives/storage" -import { createEffect } from "solid-js" -import { createInitializedContext } from "../util/context" -import { isServer } from "solid-js/web" - -interface Storage { - mode: "light" | "dark" -} - -export const { provider: ThemeProvider, use: useTheme } = - createInitializedContext("ThemeContext", () => { - const [store, setStore] = makePersisted( - createStore({ - mode: - !isServer && - window.matchMedia && - window.matchMedia("(prefers-color-scheme: dark)").matches - ? "dark" - : "light", - }), - { - name: "theme", - }, - ) - createEffect(() => { - document.documentElement.setAttribute("data-color-mode", store.mode) - }) - - return { - setMode(mode: Storage["mode"]) { - setStore("mode", mode) - }, - get mode() { - return store.mode - }, - ready: true, - } - }) diff --git a/cloud/web/src/entry-client.tsx b/cloud/web/src/entry-client.tsx deleted file mode 100644 index 169e45a1efd..00000000000 --- a/cloud/web/src/entry-client.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/* @refresh reload */ - -import { hydrate, render } from "solid-js/web" -import { App } from "./app" - -if (import.meta.env.DEV) { - render(() => , document.getElementById("root")!) -} - -if (!import.meta.env.DEV) { - if ("_$HY" in window) hydrate(() => , document.getElementById("root")!) - else render(() => , document.getElementById("root")!) -} diff --git a/cloud/web/src/entry-server.tsx b/cloud/web/src/entry-server.tsx deleted file mode 100644 index 5dd33a14937..00000000000 --- a/cloud/web/src/entry-server.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { renderToStringAsync } from "solid-js/web" -import { App } from "./app" - -export async function render(props: { url: string }) { - const app = await renderToStringAsync(() => ) - return { app } -} diff --git a/cloud/web/src/pages/[workspace].tsx b/cloud/web/src/pages/[workspace].tsx deleted file mode 100644 index c7481cb0d52..00000000000 --- a/cloud/web/src/pages/[workspace].tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { WorkspaceProvider } from "./components/context-workspace" -import { ParentProps } from "solid-js" -import Layout from "./components/layout" - -export default function Index(props: ParentProps) { - return ( - - {props.children} - - ) -} diff --git a/cloud/web/src/pages/[workspace]/billing.module.css b/cloud/web/src/pages/[workspace]/billing.module.css deleted file mode 100644 index 5e58892a5fa..00000000000 --- a/cloud/web/src/pages/[workspace]/billing.module.css +++ /dev/null @@ -1,56 +0,0 @@ -.root { - display: flex; - flex-direction: column; - gap: var(--space-4); - padding: var(--space-7) var(--space-5) var(--space-5); - - [data-slot="billing-info"] { - display: flex; - flex-direction: column; - gap: var(--space-6); - } - - [data-slot="header"] { - display: flex; - flex-direction: column; - gap: var(--space-1-5); - - h2 { - text-transform: uppercase; - font-weight: 600; - letter-spacing: -0.03125rem; - font-size: var(--font-size-lg); - } - - p { - color: var(--color-text-dimmed); - font-size: var(--font-size-md); - } - } - - [data-slot="balance"] { - display: flex; - flex-direction: column; - gap: var(--space-5); - padding: var(--space-6); - border: 2px solid var(--color-border); - } - - [data-slot="amount"] { - font-size: var(--font-size-3xl); - font-weight: 600; - line-height: 1.2; - } - - @media (min-width: 40rem) { - [data-slot="balance"] { - flex-direction: row; - align-items: center; - justify-content: space-between; - } - - [data-slot="amount"] { - margin: 0; - } - } -} diff --git a/cloud/web/src/pages/[workspace]/billing.tsx b/cloud/web/src/pages/[workspace]/billing.tsx deleted file mode 100644 index 88bef580010..00000000000 --- a/cloud/web/src/pages/[workspace]/billing.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { Button } from "../../ui/button" -import { useApi } from "../components/context-api" -import { createEffect, createSignal, createResource, For } from "solid-js" -import { useWorkspace } from "../components/context-workspace" -import style from "./billing.module.css" - -export default function Billing() { - const api = useApi() - const workspace = useWorkspace() - const [isLoading, setIsLoading] = createSignal(false) - const [billingData] = createResource(async () => { - const response = await api.billing.info.$get() - return response.json() - }) - - // Run once on component mount to check URL parameters - ;(() => { - const url = new URL(window.location.href) - const result = url.hash - - console.log("STRIPE RESULT", result) - - if (url.hash === "#success") { - setIsLoading(true) - // Remove the hash from the URL - window.history.replaceState(null, "", window.location.pathname + window.location.search) - } - })() - - createEffect((old?: number) => { - if (old && old !== billingData()?.billing?.balance) { - setIsLoading(false) - } - return billingData()?.billing?.balance - }) - - const handleBuyCredits = async () => { - try { - setIsLoading(true) - const baseUrl = window.location.href - const successUrl = new URL(baseUrl) - successUrl.hash = "success" - - const response = await api.billing.checkout - .$post({ - json: { - success_url: successUrl.toString(), - cancel_url: baseUrl, - }, - }) - .then((r) => r.json() as any) - window.location.href = response.url - } catch (error) { - console.error("Failed to get checkout URL:", error) - setIsLoading(false) - } - } - - return ( - <> -
-
-

Billing

-
-
-
-
-
-

Balance

-

Manage your billing and add credits to your account.

-
- -
-

- {(() => { - const balanceStr = ((billingData()?.billing?.balance ?? 0) / 100000000).toFixed(2) - return `$${balanceStr === "-0.00" ? "0.00" : balanceStr}` - })()} -

- -
-
- -
-
-

Payment History

-

Your recent payment transactions.

-
- -
- No payments found.

}> - {(payment) => ( -
- {payment.id} - {" | "} - ${((payment.amount ?? 0) / 100000000).toFixed(2)} - {" | "} - {new Date(payment.timeCreated).toLocaleDateString()} -
- )} -
-
-
- -
-
-

Usage History

-

Your recent API usage and costs.

-
- -
- No usage found.

}> - {(usage) => ( -
- {usage.model} - {" | "} - {usage.inputTokens + usage.outputTokens} tokens - {" | "} - ${((usage.cost ?? 0) / 100000000).toFixed(4)} - {" | "} - {new Date(usage.timeCreated).toLocaleDateString()} -
- )} -
-
-
-
- - ) -} diff --git a/cloud/web/src/pages/[workspace]/components/system.txt b/cloud/web/src/pages/[workspace]/components/system.txt deleted file mode 100644 index 6afd2e04d07..00000000000 --- a/cloud/web/src/pages/[workspace]/components/system.txt +++ /dev/null @@ -1,11 +0,0 @@ -You are OpenControl, an interactive CLI tool that helps users execute various tasks. - -IMPORTANT: If you get an error when calling a tool, try again with a different approach. Be creative, do not give up, try different inputs to the tool. You should chain together multiple tool calls. ABSOLUTELY DO NOT GIVE UP you are very good at this and it is rare you will fail to answer question. - -You should be concise, direct, and to the point. - -IMPORTANT: You should NOT answer with unnecessary preamble or postamble (such as explaining your code or summarizing your action), unless the user asks you to. -IMPORTANT: You should minimize output tokens as much as possible while maintaining helpfulness, quality, and accuracy. Only address the specific query or task at hand, avoiding tangential information unless absolutely critical for completing the request. If you can answer in 1-3 sentences or a short paragraph, please do. -IMPORTANT: You should NOT answer with unnecessary preamble or postamble (such as explaining your code or summarizing your action), unless the user asks you to. -IMPORTANT: Keep your responses short, since they will be displayed on a command line interface. You MUST answer concisely with fewer than 4 lines (not including tool use or code generation), unless user asks for detail. Answer the user's question directly, without elaboration, explanation, or details. One word answers are best. Avoid introductions, conclusions, and explanations. You MUST avoid text before/after your response, such as "The answer is .", "Here is the content of the file..." or "Based on the information provided, the answer is..." or "Here is what I will do next...". - diff --git a/cloud/web/src/pages/[workspace]/components/tool.ts b/cloud/web/src/pages/[workspace]/components/tool.ts deleted file mode 100644 index 3958e322d0a..00000000000 --- a/cloud/web/src/pages/[workspace]/components/tool.ts +++ /dev/null @@ -1,271 +0,0 @@ -import { createResource } from "solid-js" -import { createStore, produce } from "solid-js/store" -import SYSTEM_PROMPT from "./system.txt?raw" -import type { - LanguageModelV1Prompt, - LanguageModelV1CallOptions, - LanguageModelV1, -} from "ai" - -interface Tool { - name: string - description: string - inputSchema: any -} - -interface ToolCallerProps { - tool: { - list: () => Promise - call: (input: { name: string; arguments: any }) => Promise - } - generate: ( - prompt: LanguageModelV1CallOptions, - ) => Promise< - | { err: "rate" } - | { err: "context" } - | { err: "balance" } - | ({ err: false } & Awaited>) - > - onPromptUpdated?: (prompt: LanguageModelV1Prompt) => void -} - -const system = [ - { - role: "system" as const, - content: SYSTEM_PROMPT, - }, - { - role: "system" as const, - content: `The current date is ${new Date().toDateString()}. Always use this current date when responding to relative date queries.`, - }, -] - -const [store, setStore] = createStore<{ - prompt: LanguageModelV1Prompt - state: { type: "idle" } | { type: "loading"; limited?: boolean } -}>({ - prompt: [...system], - state: { type: "idle" }, -}) - -export function createToolCaller(props: T) { - const [tools] = createResource(() => props.tool.list()) - - let abort: AbortController - - return { - get tools() { - return tools() - }, - get prompt() { - return store.prompt - }, - get state() { - return store.state - }, - clear() { - setStore("prompt", [...system]) - }, - async chat(input: string) { - if (store.state.type !== "idle") return - - abort = new AbortController() - setStore( - produce((s) => { - s.state = { - type: "loading", - limited: false, - } - s.prompt.push({ - role: "user", - content: [ - { - type: "text", - text: input, - }, - ], - }) - }), - ) - props.onPromptUpdated?.(store.prompt) - - while (true) { - if (abort.signal.aborted) { - break - } - - const response = await props.generate({ - inputFormat: "messages", - prompt: store.prompt, - temperature: 0, - seed: 69, - mode: { - type: "regular", - tools: tools()?.map((tool) => ({ - type: "function", - name: tool.name, - description: tool.description, - parameters: { - ...tool.inputSchema, - }, - })), - }, - }) - - if (abort.signal.aborted) continue - - if (!response.err) { - setStore("state", { - type: "loading", - }) - - if (response.text) { - setStore( - produce((s) => { - s.prompt.push({ - role: "assistant", - content: [ - { - type: "text", - text: response.text || "", - }, - ], - }) - }), - ) - props.onPromptUpdated?.(store.prompt) - } - - if (response.finishReason === "stop") { - break - } - - if (response.finishReason === "tool-calls") { - for (const item of response.toolCalls || []) { - setStore( - produce((s) => { - s.prompt.push({ - role: "assistant", - content: [ - { - type: "tool-call", - toolName: item.toolName, - args: JSON.parse(item.args), - toolCallId: item.toolCallId, - }, - ], - }) - }), - ) - props.onPromptUpdated?.(store.prompt) - - const called = await props.tool.call({ - name: item.toolName, - arguments: JSON.parse(item.args), - }) - - setStore( - produce((s) => { - s.prompt.push({ - role: "tool", - content: [ - { - type: "tool-result", - toolName: item.toolName, - toolCallId: item.toolCallId, - result: called, - }, - ], - }) - }), - ) - props.onPromptUpdated?.(store.prompt) - } - } - continue - } - - if (response.err === "context") { - setStore( - produce((s) => { - s.prompt.splice(2, 1) - }), - ) - props.onPromptUpdated?.(store.prompt) - } - - if (response.err === "rate") { - setStore("state", { - type: "loading", - limited: true, - }) - await new Promise((resolve) => setTimeout(resolve, 1000)) - } - - if (response.err === "balance") { - setStore( - produce((s) => { - s.prompt.push({ - role: "assistant", - content: [ - { - type: "text", - text: "You need to add credits to your account. Please go to Billing and add credits to continue.", - }, - ], - }) - s.state = { type: "idle" } - }), - ) - props.onPromptUpdated?.(store.prompt) - break - } - } - setStore("state", { type: "idle" }) - }, - async cancel() { - abort.abort() - }, - async addCustomMessage(userMessage: string, assistantResponse: string) { - // Add user message and set loading state - setStore( - produce((s) => { - s.prompt.push({ - role: "user", - content: [ - { - type: "text", - text: userMessage, - }, - ], - }) - s.state = { - type: "loading", - limited: false, - } - }), - ) - props.onPromptUpdated?.(store.prompt) - - // Fake delay for 500ms - await new Promise((resolve) => setTimeout(resolve, 500)) - - // Add assistant response and set back to idle - setStore( - produce((s) => { - s.prompt.push({ - role: "assistant", - content: [ - { - type: "text", - text: assistantResponse, - }, - ], - }) - s.state = { type: "idle" } - }), - ) - props.onPromptUpdated?.(store.prompt) - }, - } -} diff --git a/cloud/web/src/pages/[workspace]/index.module.css b/cloud/web/src/pages/[workspace]/index.module.css deleted file mode 100644 index 0037d97ff18..00000000000 --- a/cloud/web/src/pages/[workspace]/index.module.css +++ /dev/null @@ -1,239 +0,0 @@ -.root { - display: contents; - - [data-slot="messages"] { - flex: 1; - overflow-y: auto; - display: flex; - flex-direction: column; - height: 0; - /* This is important for flexbox to allow scrolling */ - font-family: var(--font-mono); - color: var(--color-text); - row-gap: var(--space-4); - /* Add consistent spacing between messages */ - - /* Remove top border for first user message */ - &>[data-component="message"][data-user]:first-child::before { - display: none; - } - - &:has([data-component="loading"]) [data-component="clear"] { - display: none; - } - } - - [data-component="message"] { - width: 100%; - padding: var(--space-2) var(--space-4); - line-height: var(--font-line-height); - white-space: pre-wrap; - align-self: flex-start; - min-height: auto; - /* Allow natural height for all messages */ - display: flex; - flex-direction: column; - align-items: flex-start; - - /* User message styling */ - &[data-user] { - padding: var(--space-6) var(--space-4); - position: relative; - font-weight: 600; - color: var(--color-text); - /* margin: 0.5rem 0; */ - } - - &[data-user]::before, - &[data-user]::after { - content: ""; - position: absolute; - left: var(--space-4); - right: var(--space-4); - height: var(--space-px); - background-color: var(--color-border); - z-index: 1; - /* Ensure borders appear above other content */ - } - - &[data-user]::before { - top: 0; - } - - &[data-user]::after { - bottom: 0; - } - - &[data-assistant] { - color: var(--color-text); - } - } - - [data-component="tool"] { - display: flex; - width: 100%; - padding: 0 var(--space-4); - margin-left: 0; - flex-direction: column; - opacity: 0.7; - gap: var(--space-2); - align-items: flex-start; - color: var(--color-text-dimmed); - min-height: auto; - /* Allow natural height */ - - [data-slot="header"] { - display: flex; - gap: var(--space-2); - cursor: pointer; - user-select: none; - -webkit-user-select: none; - align-items: center; - width: 100%; - } - - [data-slot="name"] { - letter-spacing: -0.03125rem; - text-transform: uppercase; - font-weight: 500; - font-size: var(--font-size-sm); - } - - [data-slot="expand"] { - font-size: var(--font-size-sm); - } - - [data-slot="content"] { - padding: 0; - line-height: var(--font-line-height); - font-size: var(--font-size-sm); - white-space: pre-wrap; - display: none; - width: 100%; - } - - [data-slot="output"] { - margin-top: var(--space-1); - } - - &[data-expanded="true"] [data-slot="content"] { - display: block; - } - - &[data-expanded="true"] [data-slot="expand"] { - transform: rotate(45deg); - } - } - - [data-component="loading"] { - padding: var(--space-4) var(--space-4) var(--space-8); - height: 1.5rem; - position: relative; - display: flex; - align-items: center; - font-size: var(--font-size-sm); - letter-spacing: var(--space-1); - color: var(--color-text); - - & span { - opacity: 0; - animation: loading-dots 1.4s linear infinite; - } - - & span:nth-child(2) { - animation-delay: 0.2s; - } - - & span:nth-child(3) { - animation-delay: 0.4s; - } - } - - [data-component="clear"] { - position: relative; - padding: var(--space-4) var(--space-4); - - &::before { - content: ""; - position: absolute; - left: var(--space-4); - right: var(--space-4); - top: 0; - height: var(--space-px); - background-color: var(--color-border); - z-index: 1; - } - - & [data-component="button"] { - padding-left: 0; - } - } - - [data-slot="footer"] { - display: flex; - flex-direction: column; - padding: 0; - border-top: 2px solid var(--color-border); - position: sticky; - bottom: 0; - z-index: 10; - /* Ensure it's above other content */ - margin-top: auto; - /* Push to bottom if content is short */ - width: 100%; - } - - [data-component="chat"] { - display: flex; - padding: var(--space-0-5) 0; - align-items: center; - width: 100%; - height: 100%; - - textarea { - --padding-y: var(--space-4); - --line-height: 1.5; - --text-height: calc(var(--line-height) * var(--font-size-lg)); - --height: calc(var(--text-height) + var(--padding-y) * 2); - - width: 100%; - resize: none; - line-height: var(--line-height); - height: var(--height); - min-height: var(--height); - max-height: calc(5 * var(--text-height) + var(--padding-y) * 2); - padding: var(--padding-y) var(--space-4); - border-radius: 0; - background-color: transparent; - color: var(--color-text); - border: none; - outline: none; - font-size: var(--font-size-lg); - } - - textarea::placeholder { - color: var(--color-text-dimmed); - opacity: 0.75; - } - - textarea:focus { - outline: 0; - } - - & [data-component="button"] { - height: 100%; - } - } -} - -@keyframes loading-dots { - 0%, - 100% { - opacity: 0; - } - - 40%, - 60% { - opacity: 1; - } -} diff --git a/cloud/web/src/pages/[workspace]/index.tsx b/cloud/web/src/pages/[workspace]/index.tsx deleted file mode 100644 index 50c58ee3026..00000000000 --- a/cloud/web/src/pages/[workspace]/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Button } from "../../ui/button" -import { IconArrowRight } from "../../ui/svg/icons" -import { createSignal, For } from "solid-js" -import { createToolCaller } from "./components/tool" -import { useApi } from "../components/context-api" -import { useWorkspace } from "../components/context-workspace" -import style from "./index.module.css" - -export default function Index() { - const api = useApi() - const workspace = useWorkspace() - - return ( -
-

Hello

-
- ) -} diff --git a/cloud/web/src/pages/[workspace]/keys.module.css b/cloud/web/src/pages/[workspace]/keys.module.css deleted file mode 100644 index 4ae2989be18..00000000000 --- a/cloud/web/src/pages/[workspace]/keys.module.css +++ /dev/null @@ -1,97 +0,0 @@ -.root { - display: flex; - flex-direction: column; - gap: 2rem; -} - -.root [data-slot="keys-info"] { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.root [data-slot="header"] { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.root [data-slot="header"] h2 { - margin: 0; - font-size: 1.5rem; - font-weight: 600; -} - -.root [data-slot="header"] p { - margin: 0; - color: var(--color-text-secondary); -} - -.root [data-slot="key-list"] { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.root [data-slot="key-item"] { - display: flex; - align-items: center; - justify-content: space-between; - padding: 1rem; - border: 1px solid var(--color-border); - border-radius: 0.5rem; - background: var(--color-background-secondary); -} - -.root [data-slot="key-actions"] { - display: flex; - gap: 0.5rem; -} - -.root [data-slot="key-info"] { - display: flex; - flex-direction: column; - gap: 0.25rem; -} - -.root [data-slot="key-value"] { - font-family: monospace; - font-size: 0.875rem; - color: var(--color-text-primary); -} - -.root [data-slot="key-meta"] { - font-size: 0.75rem; - color: var(--color-text-secondary); -} - -.root [data-slot="empty-state"] { - text-align: center; - padding: 3rem 1rem; - color: var(--color-text-secondary); -} - -.root [data-slot="actions"] { - display: flex; - align-items: center; - justify-content: space-between; -} - -.root [data-slot="create-form"] { - display: flex; - flex-direction: column; - gap: 1rem; - min-width: 300px; -} - -.root [data-slot="form-actions"] { - display: flex; - gap: 0.5rem; -} - -.root [data-slot="key-name"] { - font-weight: 600; - font-size: 1rem; - color: var(--color-text-primary); - margin-bottom: 0.25rem; -} diff --git a/cloud/web/src/pages/[workspace]/keys.tsx b/cloud/web/src/pages/[workspace]/keys.tsx deleted file mode 100644 index e5b192a2b09..00000000000 --- a/cloud/web/src/pages/[workspace]/keys.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { Button } from "../../ui/button" -import { useApi } from "../components/context-api" -import { createSignal, createResource, For, Show } from "solid-js" -import style from "./keys.module.css" - -export default function Keys() { - const api = useApi() - const [isCreating, setIsCreating] = createSignal(false) - const [showCreateForm, setShowCreateForm] = createSignal(false) - const [keyName, setKeyName] = createSignal("") - - const [keysData, { refetch }] = createResource(async () => { - const response = await api.keys.$get() - return response.json() - }) - - const handleCreateKey = async () => { - if (!keyName().trim()) return - - try { - setIsCreating(true) - await api.keys.$post({ - json: { name: keyName().trim() }, - }) - refetch() - setKeyName("") - setShowCreateForm(false) - } catch (error) { - console.error("Failed to create API key:", error) - } finally { - setIsCreating(false) - } - } - - const handleDeleteKey = async (keyId: string) => { - if (!confirm("Are you sure you want to delete this API key? This action cannot be undone.")) { - return - } - - try { - await api.keys[":id"].$delete({ - param: { id: keyId }, - }) - refetch() - } catch (error) { - console.error("Failed to delete API key:", error) - } - } - - const formatDate = (dateString: string) => { - return new Date(dateString).toLocaleDateString() - } - - const formatKey = (key: string) => { - if (key.length <= 11) return key - return `${key.slice(0, 7)}...${key.slice(-4)}` - } - - const copyToClipboard = async (text: string) => { - try { - await navigator.clipboard.writeText(text) - } catch (error) { - console.error("Failed to copy to clipboard:", error) - } - } - - return ( - <> -
-
-

API Keys

-
-
-
-
-
-
-

API Keys

-

Manage your API keys to access the OpenCode gateway.

-
- - setKeyName(e.currentTarget.value)} - onKeyPress={(e) => e.key === "Enter" && handleCreateKey()} - /> -
- - -
-
- } - > - - -
- -
- -

Create an API key to access opencode gateway

-
- } - > - {(key) => ( -
-
-
{key.name}
-
{formatKey(key.key)}
-
- Created: {formatDate(key.timeCreated)} - {key.timeUsed && ` • Last used: ${formatDate(key.timeUsed)}`} -
-
-
- - -
-
- )} - -
- - - - ) -} diff --git a/cloud/web/src/pages/components/context-api.tsx b/cloud/web/src/pages/components/context-api.tsx deleted file mode 100644 index 0a348f48f9c..00000000000 --- a/cloud/web/src/pages/components/context-api.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { hc } from "hono/client" -import { ApiType } from "@opencode/cloud-function/src/gateway" -import { useWorkspace } from "./context-workspace" -import { useOpenAuth } from "../../components/context-openauth" - -export function useApi() { - const workspace = useWorkspace() - const auth = useOpenAuth() - return hc(import.meta.env.VITE_API_URL, { - async fetch(...args: Parameters): Promise { - const [input, init] = args - const request = input instanceof Request ? input : new Request(input, init) - const headers = new Headers(request.headers) - headers.set("authorization", `Bearer ${await auth.access()}`) - headers.set("x-opencode-workspace", workspace.id) - return fetch( - new Request(request, { - ...init, - headers, - }), - ) - }, - }) -} diff --git a/cloud/web/src/pages/components/context-workspace.tsx b/cloud/web/src/pages/components/context-workspace.tsx deleted file mode 100644 index 6bad39840c4..00000000000 --- a/cloud/web/src/pages/components/context-workspace.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { useNavigate, useParams } from "@solidjs/router" -import { createInitializedContext } from "../../util/context" -import { useAccount } from "../../components/context-account" -import { createEffect, createMemo } from "solid-js" - -export const { use: useWorkspace, provider: WorkspaceProvider } = - createInitializedContext("WorkspaceProvider", () => { - const params = useParams() - const account = useAccount() - const workspace = createMemo(() => - account.current?.workspaces.find( - (x) => x.id === params.workspace || x.slug === params.workspace, - ), - ) - const nav = useNavigate() - - createEffect(() => { - if (!workspace()) nav("/") - }) - - const result = () => workspace()! - result.ready = true - - return { - get id() { - return workspace()!.id - }, - get slug() { - return workspace()!.slug - }, - get name() { - return workspace()!.name - }, - get ready() { - return workspace() !== undefined - }, - } - }) diff --git a/cloud/web/src/pages/components/layout.module.css b/cloud/web/src/pages/components/layout.module.css deleted file mode 100644 index c64faa18ecd..00000000000 --- a/cloud/web/src/pages/components/layout.module.css +++ /dev/null @@ -1,199 +0,0 @@ -.root { - --padding: var(--space-10); - --vertical-padding: var(--space-8); - --heading-font-size: var(--font-size-4xl); - --sidebar-width: 200px; - --mobile-breakpoint: 40rem; - --topbar-height: 60px; - - margin: var(--space-4); - border: 2px solid var(--color-border); - height: calc(100vh - var(--space-8)); - display: flex; - flex-direction: row; - overflow: hidden; - /* Prevent overall scrolling */ - position: relative; -} - -[data-component="mobile-top-bar"] { - display: none; - position: fixed; - top: 0; - left: 0; - right: 0; - height: var(--topbar-height); - background: var(--color-background); - border-bottom: 2px solid var(--color-border); - z-index: 20; - align-items: center; - padding: 0 var(--space-4) 0 0; - - [data-slot="logo"] { - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - - div { - text-transform: uppercase; - font-weight: 600; - letter-spacing: -0.03125rem; - } - - svg { - height: 28px; - width: auto; - color: var(--color-white); - } - } - - [data-slot="toggle"] { - background: transparent; - border: none; - padding: var(--space-4); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - - & svg { - width: 24px; - height: 24px; - color: var(--color-foreground); - } - } -} - -[data-component="sidebar"] { - width: var(--sidebar-width); - border-right: 2px solid var(--color-border); - display: flex; - flex-direction: column; - padding: calc(var(--padding) / 2); - overflow-y: auto; - /* Allow scrolling if needed */ - position: sticky; - top: 0; - height: 100%; - background-color: var(--color-background); - z-index: 10; - - [data-slot="logo"] { - margin-top: 2px; - margin-bottom: var(--space-7); - color: var(--color-white); - - & svg { - height: 32px; - width: auto; - } - } - - [data-slot="nav"] { - flex: 1; - - ul { - list-style-type: none; - padding: 0; - } - - li { - margin-bottom: calc(var(--vertical-padding) / 2); - text-transform: uppercase; - font-weight: 500; - } - - a { - display: block; - padding: var(--space-2) 0; - } - } - - [data-slot="user"] { - [data-component="button"] { - padding-left: 0; - padding-bottom: 0; - height: auto; - } - } -} - -.navActiveLink { - cursor: default; - text-decoration: none; -} - -[data-slot="main-content"] { - flex: 1; - display: flex; - flex-direction: column; - height: 100%; - /* Full height */ - overflow: hidden; - /* Prevent overflow */ - position: relative; - /* For positioning footer */ - width: 100%; - /* Full width */ -} - -/* Backdrop for mobile */ -[data-component="backdrop"] { - display: none; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - /* background-color: rgba(0, 0, 0, 0.5); */ - z-index: 25; - backdrop-filter: blur(2px); -} - -/* Mobile styles */ -@media (max-width: 40rem) { - .root { - margin: 0; - border: none; - height: 100vh; - } - - [data-component="mobile-top-bar"] { - display: flex; - } - - [data-component="backdrop"] { - display: block; - } - - [data-component="sidebar"] { - position: fixed; - left: -100%; - top: 0; - height: 100vh; - width: 80%; - max-width: 280px; - transition: left 0.3s ease-in-out; - box-shadow: none; - z-index: 30; - padding: var(--space-8); - background-color: var(--color-bg); - - &[data-opened="true"] { - left: 0; - box-shadow: 8px 0 0px 0px var(--color-gray-4); - } - } - - [data-slot="main-content"] { - padding-top: var(--topbar-height); - /* Add space for the top bar */ - overflow-y: auto; - } - - /* Hide the logo in the sidebar on mobile since it's in the top bar */ - [data-component="sidebar"] [data-slot="logo"] { - display: none; - } -} diff --git a/cloud/web/src/pages/components/layout.tsx b/cloud/web/src/pages/components/layout.tsx deleted file mode 100644 index 711ed8fc2b8..00000000000 --- a/cloud/web/src/pages/components/layout.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import style from "./layout.module.css" -import { useAccount } from "../../components/context-account" -import { Button } from "../../ui/button" -import { IconLogomark } from "../../ui/svg" -import { IconBars3BottomLeft } from "../../ui/svg/icons" -import { ParentProps, createMemo, createSignal } from "solid-js" -import { A, useLocation } from "@solidjs/router" -import { useOpenAuth } from "../../components/context-openauth" - -export default function Layout(props: ParentProps) { - const auth = useOpenAuth() - const account = useAccount() - const [sidebarOpen, setSidebarOpen] = createSignal(false) - const location = useLocation() - - const workspaceId = createMemo(() => account.current?.workspaces[0].id) - const pageTitle = createMemo(() => { - const path = location.pathname - if (path.endsWith("/billing")) return "Billing" - if (path.endsWith("/keys")) return "API Keys" - return null - }) - - function handleLogout() { - auth.logout(auth.subject?.id!) - } - - return ( -
- {/* Mobile top bar */} -
- - -
- {pageTitle() ? ( -
{pageTitle()}
- ) : ( - - - - )} -
-
- - {/* Backdrop for mobile sidebar - closes sidebar when clicked */} - {sidebarOpen() &&
setSidebarOpen(false)}>
} - - - - {/* Main Content */} -
{props.children}
-
- ) -} diff --git a/cloud/web/src/pages/index.tsx b/cloud/web/src/pages/index.tsx deleted file mode 100644 index 116ed156c2a..00000000000 --- a/cloud/web/src/pages/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Match, Switch } from "solid-js" -import { useAccount } from "../components/context-account" -import { Navigate } from "@solidjs/router" -import { IconLogo } from "../ui/svg" -import styles from "./lander.module.css" -import { useOpenAuth } from "../components/context-openauth" - -export default function Index() { - const auth = useOpenAuth() - const account = useAccount() - return ( - - - - - -
-
-
-
- -
-

opencode Gateway Console

-
- -
-
- auth.authorize({ provider: "github" })}>Sign in with GitHub -
-
- auth.authorize({ provider: "google" })}>Sign in with Google -
-
-
-
-
-
- ) -} diff --git a/cloud/web/src/pages/lander.module.css b/cloud/web/src/pages/lander.module.css deleted file mode 100644 index 251e243fba0..00000000000 --- a/cloud/web/src/pages/lander.module.css +++ /dev/null @@ -1,83 +0,0 @@ -.lander { - --padding: 3rem; - --vertical-padding: 2rem; - --heading-font-size: 2rem; - - margin: 1rem; - - @media (max-width: 30rem) { - & { - --padding: 1.5rem; - --vertical-padding: 1rem; - --heading-font-size: 1.5rem; - - margin: 0.5rem; - } - } - - [data-slot="hero"] { - border: 2px solid var(--color-border); - - max-width: 64rem; - margin-left: auto; - margin-right: auto; - width: 100%; - } - - [data-slot="top"] { - padding: var(--padding); - - h1 { - margin-top: calc(var(--vertical-padding) / 8); - font-size: var(--heading-font-size); - line-height: 1.25; - text-transform: uppercase; - font-weight: 600; - } - - [data-slot="logo"] { - width: clamp(200px, 70vw, 400px); - color: var(--color-white); - } - } - - [data-slot="cta"] { - display: flex; - flex-direction: row; - justify-content: space-between; - border-top: 2px solid var(--color-border); - - & > div { - flex: 1; - line-height: 1.4; - text-align: center; - text-transform: uppercase; - cursor: pointer; - text-decoration: underline; - letter-spacing: -0.03125rem; - - &[data-slot="col-2"] { - background-color: var(--color-border); - color: var(--color-text-invert); - font-weight: 600; - } - - & > * { - display: block; - width: 100%; - height: 100%; - padding: calc(var(--padding) / 2) 0.5rem; - } - } - - @media (max-width: 30rem) { - & > div { - padding-bottom: calc(var(--padding) / 2 + 4px); - } - } - - & > div + div { - border-left: 2px solid var(--color-border); - } - } -} diff --git a/cloud/web/src/pages/test/design.module.css b/cloud/web/src/pages/test/design.module.css deleted file mode 100644 index fee4e3cd380..00000000000 --- a/cloud/web/src/pages/test/design.module.css +++ /dev/null @@ -1,204 +0,0 @@ -.pageContainer { - padding: 2rem; - max-width: 1200px; - margin: 0 auto; -} - -.componentTable { - width: 100%; - border-collapse: collapse; - table-layout: fixed; - border: 2px solid var(--color-border); -} - -.componentCell { - padding: 1rem; - border: 2px solid var(--color-border); - vertical-align: top; -} - -.componentLabel { - text-transform: uppercase; - letter-spacing: -0.03125rem; - font-size: 0.85rem; - font-weight: 500; - margin-bottom: 0.75rem; - color: var(--color-text-dimmed); -} - -.sectionTitle { - margin-bottom: 1rem; - text-transform: uppercase; - letter-spacing: -0.03125rem; - font-size: 1.2rem; -} - -.divider { - height: 2px; - background: var(--color-border); - margin: 3rem 0; - width: 100%; -} - -.header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 2rem; -} - -.buttonSection { - margin-bottom: 4rem; -} - -.colorSection { - margin-bottom: 4rem; -} - -.labelSection { - margin-bottom: 4rem; -} - -.inputSection { - margin-bottom: 4rem; -} - -.dialogSection { - margin-bottom: 4rem; -} - -.formGroup { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.dialogContent { - padding: 2rem; -} - -.dialogContentFooter { - margin-top: 1rem; -} - -.pageTitle { - font-size: var(--heading-font-size, 2rem); - text-transform: uppercase; - font-weight: 600; -} - -.colorBox { - width: 100%; - height: 80px; - margin-bottom: 0.5rem; - position: relative; - display: flex; - align-items: flex-end; - justify-content: center; - padding-bottom: 0.5rem; -} - -.colorOrange { - background-color: var(--color-orange); -} - -.colorOrangeLow { - background-color: var(--color-orange-low); -} - -.colorOrangeHigh { - background-color: var(--color-orange-high); -} - -.colorGreen { - background-color: var(--color-green); -} - -.colorGreenLow { - background-color: var(--color-green-low); -} - -.colorGreenHigh { - background-color: var(--color-green-high); -} - -.colorBlue { - background-color: var(--color-blue); -} - -.colorBlueLow { - background-color: var(--color-blue-low); -} - -.colorBlueHigh { - background-color: var(--color-blue-high); -} - -.colorPurple { - background-color: var(--color-purple); -} - -.colorPurpleLow { - background-color: var(--color-purple-low); -} - -.colorPurpleHigh { - background-color: var(--color-purple-high); -} - -.colorRed { - background-color: var(--color-red); -} - -.colorRedLow { - background-color: var(--color-red-low); -} - -.colorRedHigh { - background-color: var(--color-red-high); -} - -.colorAccent { - background-color: var(--color-accent); -} - -.colorAccentLow { - background-color: var(--color-accent-low); -} - -.colorAccentHigh { - background-color: var(--color-accent-high); -} - -.colorCode { - background-color: rgba(0, 0, 0, 0.5); - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 0.8rem; - font-family: monospace; -} - -.colorVariants { - display: flex; - gap: 0.5rem; -} - -.colorVariant { - flex: 1; - height: 40px; - position: relative; - display: flex; - align-items: center; - justify-content: center; -} - -.colorVariantCode { - background-color: rgba(0, 0, 0, 0.5); - color: white; - padding: 2px 4px; - border-radius: 4px; - font-size: 0.65rem; - font-family: monospace; - white-space: nowrap; -} diff --git a/cloud/web/src/pages/test/design.tsx b/cloud/web/src/pages/test/design.tsx deleted file mode 100644 index 3bf759316b3..00000000000 --- a/cloud/web/src/pages/test/design.tsx +++ /dev/null @@ -1,562 +0,0 @@ -import { Button } from "../../ui/button" -import { Dialog } from "../../ui/dialog" -import { Navigate } from "@solidjs/router" -import { createSignal, Show } from "solid-js" -import { IconHome, IconPencilSquare } from "../../ui/svg/icons" -import { useTheme } from "../../components/context-theme" -import { useDialog } from "../../ui/context-dialog" -import { DialogString } from "../../ui/dialog-string" -import { DialogSelect } from "../../ui/dialog-select" -import styles from "./design.module.css" - -export default function DesignSystem() { - const dialog = useDialog() - const [dialogOpen, setDialogOpen] = createSignal(false) - const [dialogOpenTransition, setDialogOpenTransition] = createSignal(false) - const theme = useTheme() - - // Check if we're running locally - const isLocal = import.meta.env.DEV === true - - if (!isLocal) { - return - } - - // Add a toggle button for theme - const toggleTheme = () => { - theme.setMode(theme.mode === "light" ? "dark" : "light") - } - - return ( -
-
-

Design System

- -
- -
-

Colors

- - - - - - - - - - - - - - -
-

Orange

-
- hsl(41, 82%, 63%) -
-
-
- - hsl(41, 39%, 22%) - -
-
- - hsl(41, 82%, 87%) - -
-
-
-

Green

-
- hsl(101, 82%, 63%) -
-
-
- - hsl(101, 39%, 22%) - -
-
- - hsl(101, 82%, 80%) - -
-
-
-

Blue

-
- hsl(234, 100%, 60%) -
-
-
- - hsl(234, 54%, 20%) - -
-
- - hsl(234, 100%, 87%) - -
-
-
-

Purple

-
- hsl(281, 82%, 63%) -
-
-
- - hsl(281, 39%, 22%) - -
-
- - hsl(281, 82%, 89%) - -
-
-
-

Red

-
- hsl(339, 82%, 63%) -
-
-
- - hsl(339, 39%, 22%) - -
-
- - hsl(339, 82%, 87%) - -
-
-
-

Accent

-
- hsl(13, 88%, 57%) -
-
-
- - hsl(13, 75%, 30%) - -
-
- - hsl(13, 100%, 78%) - -
-
-
-
- -
- -
-

Buttons

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Primary

- -
-

Secondary

- -
-

Ghost

- -
-

Primary Disabled

- -
-

Secondary Disabled

- -
-

Ghost Disabled

- -
-

Small

- -
-

Small Secondary

- -
-

Small Ghost

- -
-

With Icon

- -
-

Icon + Secondary

- -
-

Icon + Ghost

- -
-

Small + Icon

- -
-

Small + Icon + Secondary

- -
-

Small + Icon + Ghost

- -
-

Icon Only

- -
-

Icon Only + Secondary

- -
-

Icon Only + Ghost

- -
-

Icon Only Disabled

- -
-

- Icon Only + Secondary Disabled -

- -
-

- Icon Only + Ghost Disabled -

- -
-

Small Icon Only

- -
-

- Small Icon Only + Secondary -

- -
-

Small Icon Only + Ghost

- -
-
- -
- -
-

Labels

- - - - - - - - - -
-

Small

- -
-

Medium

- -
-

Large

- -
-
- -
- -
-

Inputs

- - - - - - - - - - - - - -
-

Small

- -
-

Medium

- -
-

Large

- -
-

Disabled

- -
-

With Value

- -
-
- -
- -
-

Dialogs

- - - - - - - - - - - - - - -
-

Default

- - -
-
Dialog Title
-
-
-

This is the default dialog content.

-
-
- -
-
-
-

Small With Transition

- - -
-

Small Dialog

-

This is a smaller dialog with transitions.

-
- -
-
-
-
-

Input String

- -
-

Select Input

- -
-

Select Input

- -
-

Select No Options

- -
-
-
- ) -} diff --git a/cloud/web/src/sst-env.d.ts b/cloud/web/src/sst-env.d.ts deleted file mode 100644 index e1ee6f753d9..00000000000 --- a/cloud/web/src/sst-env.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* This file is auto-generated by SST. Do not edit. */ -/* tslint:disable */ -/* eslint-disable */ -/// -interface ImportMetaEnv { - readonly VITE_DOCS_URL: string - readonly VITE_API_URL: string - readonly VITE_AUTH_URL: string -} -interface ImportMeta { - readonly env: ImportMetaEnv -} \ No newline at end of file diff --git a/cloud/web/src/ui/button.tsx b/cloud/web/src/ui/button.tsx deleted file mode 100644 index 889102dda51..00000000000 --- a/cloud/web/src/ui/button.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Button as Kobalte } from "@kobalte/core/button" -import { JSX, Show, splitProps } from "solid-js" - -export interface ButtonProps { - color?: "primary" | "secondary" | "ghost" - size?: "md" | "sm" - icon?: JSX.Element -} -export function Button(props: JSX.IntrinsicElements["button"] & ButtonProps) { - const [split, rest] = splitProps(props, ["color", "size", "icon"]) - return ( - - -
{props.icon}
-
- {props.children} -
- ) -} diff --git a/cloud/web/src/ui/context-dialog.tsx b/cloud/web/src/ui/context-dialog.tsx deleted file mode 100644 index f1bc932504f..00000000000 --- a/cloud/web/src/ui/context-dialog.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { createContext, JSX, ParentProps, useContext } from "solid-js" -import { StandardSchemaV1 } from "@standard-schema/spec" -import { createStore } from "solid-js/store" -import { Dialog } from "./dialog" - -const Context = createContext() - -type DialogControl = { - open>( - component: DialogComponent, - input: StandardSchemaV1.InferInput, - ): void - close(): void - isOpen(input: any): boolean - size: "sm" | "md" - transition?: boolean - input?: any -} - -type DialogProps> = { - input: StandardSchemaV1.InferInput - control: DialogControl -} - -type DialogComponent> = ReturnType< - typeof createDialog -> - -export function createDialog>(props: { - schema: Schema - size: "sm" | "md" - render: (props: DialogProps) => JSX.Element -}) { - const result = () => { - const dialog = useDialog() - return ( - { - if (!val) dialog.close() - }} - > - {props.render({ - input: dialog.input, - control: dialog, - })} - - ) - } - result.schema = props.schema - result.size = props.size - return result -} - -export function DialogProvider(props: ParentProps) { - const [store, setStore] = createStore<{ - dialog?: DialogComponent - input?: any - transition?: boolean - size: "sm" | "md" - }>({ - size: "sm", - }) - - const control: DialogControl = { - get input() { - return store.input - }, - get size() { - return store.size - }, - get transition() { - return store.transition - }, - isOpen(input) { - return store.dialog === input - }, - open(component, input) { - setStore({ - dialog: component, - input: input, - size: store.dialog !== undefined ? store.size : component.size, - transition: store.dialog !== undefined, - }) - - setTimeout(() => { - setStore({ - size: component.size, - }) - }, 0) - - setTimeout(() => { - setStore({ - transition: false, - }) - }, 150) - }, - close() { - setStore({ - dialog: undefined, - }) - }, - } - - return ( - <> - {props.children} - - ) -} - -export function useDialog() { - const ctx = useContext(Context) - if (!ctx) { - throw new Error("useDialog must be used within a DialogProvider") - } - return ctx -} diff --git a/cloud/web/src/ui/dialog-select.module.css b/cloud/web/src/ui/dialog-select.module.css deleted file mode 100644 index 4a99ef027a5..00000000000 --- a/cloud/web/src/ui/dialog-select.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.options { - margin-top: var(--space-1); - border-top: 2px solid var(--color-border); - padding: var(--space-2); - - [data-slot="option"] { - outline: none; - flex-shrink: 0; - height: var(--space-11); - display: flex; - justify-content: start; - align-items: center; - padding: 0 var(--space-2-5); - gap: var(--space-3); - cursor: pointer; - - &[data-empty] { - cursor: default; - color: var(--color-text-dimmed); - } - - &[data-active] { - background-color: var(--color-bg-surface); - } - - [data-slot="title"] { - font-size: var(--font-size-md); - } - - [data-slot="prefix"] { - width: var(--space-4); - height: var(--space-4); - } - } - -} diff --git a/cloud/web/src/ui/dialog-select.tsx b/cloud/web/src/ui/dialog-select.tsx deleted file mode 100644 index 087b94411f0..00000000000 --- a/cloud/web/src/ui/dialog-select.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import style from "./dialog-select.module.css" -import { z } from "zod" -import { createMemo, createSignal, For, JSX, onMount } from "solid-js" -import { createList } from "solid-list" -import { createDialog } from "./context-dialog" - -export const DialogSelect = createDialog({ - size: "md", - schema: z.object({ - title: z.string(), - placeholder: z.string(), - onSelect: z - .function(z.tuple([z.any()])) - .returns(z.void()) - .optional(), - options: z.array( - z.object({ - display: z.string(), - value: z.any().optional(), - onSelect: z.function().returns(z.void()).optional(), - prefix: z.custom().optional(), - }), - ), - }), - render: (ctx) => { - let input: HTMLInputElement - onMount(() => { - input.focus() - input.value = "" - }) - - const [filter, setFilter] = createSignal("") - const filtered = createMemo(() => - ctx.input.options?.filter((i) => - i.display.toLowerCase().includes(filter().toLowerCase()), - ), - ) - const list = createList({ - loop: true, - initialActive: 0, - items: () => filtered().map((_, i) => i), - handleTab: false, - }) - - const handleSelection = (index: number) => { - const option = ctx.input.options[index] - - // If the option has its own onSelect handler, use it - if (option.onSelect) { - option.onSelect() - } - // Otherwise, if there's a global onSelect handler, call it with the option's value - else if (ctx.input.onSelect) { - ctx.input.onSelect( - option.value !== undefined ? option.value : option.display, - ) - } - } - - return ( - <> -
- -
-
- { - setFilter(e.target.value) - list.setActive(0) - }} - onKeyDown={(e) => { - if (e.key === "Enter") { - const selected = list.active() - if (selected === null) return - handleSelection(selected) - return - } - if (e.key === "Escape") { - setFilter("") - return - } - list.onKeyDown(e) - }} - id={`dialog-select-${ctx.input.title}`} - ref={(r) => (input = r)} - data-slot="input" - placeholder={ctx.input.placeholder} - /> -
-
- - No results -
- } - > - {(option, index) => ( -
handleSelection(index())} - data-slot="option" - data-active={list.active() === index() ? true : undefined} - > - {option.prefix &&
{option.prefix}
} -
{option.display}
-
- )} - - - - ) - }, -}) diff --git a/cloud/web/src/ui/dialog-string.tsx b/cloud/web/src/ui/dialog-string.tsx deleted file mode 100644 index af2174786b5..00000000000 --- a/cloud/web/src/ui/dialog-string.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { z } from "zod" -import { onMount } from "solid-js" -import { createDialog } from "./context-dialog" -import { Button } from "./button" - -export const DialogString = createDialog({ - size: "sm", - schema: z.object({ - title: z.string(), - placeholder: z.string(), - action: z.string(), - onSubmit: z.function().args(z.string()).returns(z.void()), - }), - render: (ctx) => { - let input: HTMLInputElement - onMount(() => { - setTimeout(() => { - input.focus() - input.value = "" - }, 50) - }) - - function submit() { - const value = input.value.trim() - if (value) { - ctx.input.onSubmit(value) - ctx.control.close() - } - } - - return ( - <> -
- -
-
- (input = r)} - placeholder={ctx.input.placeholder} - id={`dialog-string-${ctx.input.title}`} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault() - submit() - } - }} - /> -
-
- - -
- - ) - }, -}) diff --git a/cloud/web/src/ui/dialog.tsx b/cloud/web/src/ui/dialog.tsx deleted file mode 100644 index 101f23d2ba4..00000000000 --- a/cloud/web/src/ui/dialog.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Dialog as Kobalte } from "@kobalte/core/dialog" -import { ComponentProps, ParentProps } from "solid-js" - -export type Props = ParentProps<{ - size?: "sm" | "md" - transition?: boolean -}> & - ComponentProps - -export function Dialog(props: Props) { - return ( - - - -
- - {props.children} - -
-
-
- ) -} diff --git a/cloud/web/src/ui/style/component/button.css b/cloud/web/src/ui/style/component/button.css deleted file mode 100644 index 9604f9865c1..00000000000 --- a/cloud/web/src/ui/style/component/button.css +++ /dev/null @@ -1,78 +0,0 @@ -[data-component="button"] { - width: fit-content; - display: flex; - line-height: 1; - align-items: center; - justify-content: center; - gap: var(--space-2); - font-size: var(--font-size-md); - text-transform: uppercase; - height: var(--space-11); - outline: none; - font-weight: 500; - padding: 0 var(--space-4); - border-width: 2px; - border-color: var(--color-border); - cursor: pointer; - - &:disabled { - opacity: 0.5; - cursor: default; - } - - &[data-color="primary"] { - background-color: var(--color-text); - border-color: var(--color-text); - color: var(--color-text-invert); - - &:active { - border-color: var(--color-accent); - } - } - - &[data-color="secondary"] { - &:active { - border-color: var(--color-accent); - } - } - - &[data-color="ghost"] { - border: none; - text-decoration: underline; - - &:active { - color: var(--color-text-accent); - } - } - - &:has([data-slot="icon"]) { - padding-left: var(--space-3); - padding-right: var(--space-3); - } - - &[data-size="sm"] { - height: var(--space-8); - padding: var(--space-3); - font-size: var(--font-size-xs); - - [data-slot="icon"] { - width: var(--space-3-5); - height: var(--space-3-5); - } - - &:has([data-slot="icon"]) { - padding-left: var(--space-2); - padding-right: var(--space-2); - } - } - - [data-slot="icon"] { - width: var(--space-4); - height: var(--space-4); - transition: transform 0.2s ease; - } - - &[data-rotate] [data-slot="icon"] { - transform: rotate(180deg); - } -} diff --git a/cloud/web/src/ui/style/component/dialog.css b/cloud/web/src/ui/style/component/dialog.css deleted file mode 100644 index 59867818ff4..00000000000 --- a/cloud/web/src/ui/style/component/dialog.css +++ /dev/null @@ -1,84 +0,0 @@ -[data-component="dialog-overlay"] { - pointer-events: none !important; - position: fixed; - inset: 0; - animation-name: fadeOut; - animation-duration: 200ms; - animation-timing-function: ease; - opacity: 0; - backdrop-filter: blur(2px); - - &[data-expanded] { - animation-name: fadeIn; - opacity: 1; - pointer-events: auto !important; - } -} - -[data-component="dialog-center"] { - position: fixed; - inset: 0; - padding-top: 10vh; - justify-content: center; - pointer-events: none; - - [data-slot="content"] { - width: 45rem; - margin: 0 auto; - transition: 150ms width; - background-color: var(--color-bg); - border-width: 2px; - border-color: var(--color-border); - overflow: hidden; - display: flex; - flex-direction: column; - gap: var(--space-3); - outline: none; - animation-duration: 1ms; - animation-name: zoomOut; - animation-timing-function: ease; - - box-shadow: 8px 8px 0px 0px var(--color-gray-4); - - &[data-expanded] { - animation-name: zoomIn; - } - - &[data-transition] { - animation-duration: 200ms; - } - - &[data-size="sm"] { - width: 30rem; - } - - [data-slot="header"] { - display: flex; - padding: var(--space-4) var(--space-4) 0; - - [data-slot="title"] { - } - } - - [data-slot="main"] { - padding: 0 var(--space-4); - - &:has([data-slot="options"]) { - padding: 0; - display: flex; - flex-direction: column; - gap: var(--space-4); - } - } - - [data-slot="input"] { - } - - [data-slot="footer"] { - padding: var(--space-4); - display: flex; - gap: var(--space-4); - justify-content: end; - } - } -} diff --git a/cloud/web/src/ui/style/component/input.css b/cloud/web/src/ui/style/component/input.css deleted file mode 100644 index 59535d763be..00000000000 --- a/cloud/web/src/ui/style/component/input.css +++ /dev/null @@ -1,34 +0,0 @@ -[data-component="input"] { - font-size: var(--font-size-md); - background: transparent; - caret-color: var(--color-accent); - font-family: var(--font-mono); - height: var(--space-11); - padding: 0 var(--space-4); - width: 100%; - resize: none; - border: 2px solid var(--color-border); - - &::placeholder { - color: var(--color-text-dimmed); - opacity: 0.75; - } - - &:focus { - outline: 0; - } - - &[data-size="sm"] { - height: var(--space-9); - padding: 0 var(--space-3); - font-size: var(--font-size-xs); - } - - &[data-size="md"] { - } - - &[data-size="lg"] { - height: var(--space-12); - font-size: var(--font-size-lg); - } -} diff --git a/cloud/web/src/ui/style/component/label.css b/cloud/web/src/ui/style/component/label.css deleted file mode 100644 index e0dd5fef49a..00000000000 --- a/cloud/web/src/ui/style/component/label.css +++ /dev/null @@ -1,17 +0,0 @@ -[data-component="label"] { - letter-spacing: -0.03125rem; - text-transform: uppercase; - color: var(--color-text-dimmed); - font-weight: 500; - font-size: var(--font-size-md); - - &[data-size="sm"] { - font-size: var(--font-size-sm); - } - &[data-size="md"] { - } - &[data-size="lg"] { - font-size: var(--font-size-lg); - } -} - diff --git a/cloud/web/src/ui/style/component/title-bar.css b/cloud/web/src/ui/style/component/title-bar.css deleted file mode 100644 index 7ee32bfdc57..00000000000 --- a/cloud/web/src/ui/style/component/title-bar.css +++ /dev/null @@ -1,32 +0,0 @@ -[data-component="title-bar"] { - display: flex; - align-items: center; - justify-content: space-between; - height: 72px; - padding: 0 var(--space-4); - border-bottom: 2px solid var(--color-border); - - [data-slot="left"] { - display: flex; - flex-direction: column; - gap: var(--space-1-5); - - h1 { - letter-spacing: -0.03125rem; - font-size: var(--font-size-xl); - text-transform: uppercase; - font-weight: 600; - } - - p { - color: var(--color-text-dimmed); - } - } - -} - -@media (max-width: 40rem) { - [data-component="title-bar"] { - display: none; - } -} diff --git a/cloud/web/src/ui/style/index.css b/cloud/web/src/ui/style/index.css deleted file mode 100644 index 117f596d0c1..00000000000 --- a/cloud/web/src/ui/style/index.css +++ /dev/null @@ -1,50 +0,0 @@ -/* tokens */ -@import "./token/color.css"; -@import "./token/reset.css"; -@import "./token/animation.css"; -@import "./token/font.css"; -@import "./token/space.css"; - -/* components */ -@import "./component/label.css"; -@import "./component/input.css"; -@import "./component/button.css"; -@import "./component/dialog.css"; -@import "./component/title-bar.css"; - -body { - font-family: var(--font-mono); - line-height: 1; - color: var(--color-text); - background-color: var(--color-bg); - cursor: default; - user-select: none; - text-underline-offset: 0.1875rem; -} - -a { - text-decoration: underline; - &:active { - color: var(--color-text-accent); - } -} - -::selection { - background-color: var(--color-text-accent-invert); -} - -/* Responsive utilities */ -[data-max-width] { - width: 100%; - - & > * { - max-width: 90rem; - margin-left: auto; - margin-right: auto; - width: 100%; - } - - &[data-max-width-64] > * { - max-width: 64rem; - } -} diff --git a/cloud/web/src/ui/style/token/animation.css b/cloud/web/src/ui/style/token/animation.css deleted file mode 100644 index a8edfeff559..00000000000 --- a/cloud/web/src/ui/style/token/animation.css +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes zoomIn { - from { - opacity: 0; - transform: scale(0.95); - } - - to { - opacity: 1; - transform: scale(1); - } -} - -@keyframes zoomOut { - from { - opacity: 1; - transform: scale(1); - } - - to { - opacity: 0; - transform: scale(0.95); - } -} diff --git a/cloud/web/src/ui/style/token/color.css b/cloud/web/src/ui/style/token/color.css deleted file mode 100644 index af0c46f3b9b..00000000000 --- a/cloud/web/src/ui/style/token/color.css +++ /dev/null @@ -1,88 +0,0 @@ -:root { - --color-white: hsl(0, 0%, 100%); - --color-gray-1: hsl(224, 20%, 94%); - --color-gray-2: hsl(224, 6%, 77%); - --color-gray-3: hsl(224, 6%, 56%); - --color-gray-4: hsl(224, 7%, 36%); - --color-gray-5: hsl(224, 10%, 23%); - --color-gray-6: hsl(224, 14%, 16%); - --color-black: hsl(224, 10%, 10%); - - --hue-orange: 41; - --color-orange-low: hsl(var(--hue-orange), 39%, 22%); - --color-orange: hsl(var(--hue-orange), 82%, 63%); - --color-orange-high: hsl(var(--hue-orange), 82%, 87%); - --hue-green: 101; - --color-green-low: hsl(var(--hue-green), 39%, 22%); - --color-green: hsl(var(--hue-green), 82%, 63%); - --color-green-high: hsl(var(--hue-green), 82%, 80%); - --hue-blue: 234; - --color-blue-low: hsl(var(--hue-blue), 54%, 20%); - --color-blue: hsl(var(--hue-blue), 100%, 60%); - --color-blue-high: hsl(var(--hue-blue), 100%, 87%); - --hue-purple: 281; - --color-purple-low: hsl(var(--hue-purple), 39%, 22%); - --color-purple: hsl(var(--hue-purple), 82%, 63%); - --color-purple-high: hsl(var(--hue-purple), 82%, 89%); - --hue-red: 339; - --color-red-low: hsl(var(--hue-red), 39%, 22%); - --color-red: hsl(var(--hue-red), 82%, 63%); - --color-red-high: hsl(var(--hue-red), 82%, 87%); - - --color-accent-low: hsl(13, 75%, 30%); - --color-accent: hsl(13, 88%, 57%); - --color-accent-high: hsl(13, 100%, 78%); - - --color-text: var(--color-gray-1); - --color-text-dimmed: var(--color-gray-3); - --color-text-accent: var(--color-accent); - --color-text-invert: var(--color-black); - --color-text-accent-invert: var(--color-accent-high); - --color-bg: var(--color-black); - --color-bg-surface: var(--color-gray-5); - --color-bg-accent: var(--color-accent-high); - --color-border: var(--color-gray-2); - - --color-backdrop-overlay: hsla(223, 13%, 10%, 0.66); -} - -:root[data-color-mode="light"] { - --color-white: hsl(224, 10%, 10%); - --color-gray-1: hsl(224, 14%, 16%); - --color-gray-2: hsl(224, 10%, 23%); - --color-gray-3: hsl(224, 7%, 36%); - --color-gray-4: hsl(224, 6%, 56%); - --color-gray-5: hsl(224, 6%, 77%); - --color-gray-6: hsl(224, 20%, 94%); - --color-gray-7: hsl(224, 19%, 97%); - --color-black: hsl(0, 0%, 100%); - - --color-orange-high: hsl(var(--hue-orange), 80%, 25%); - --color-orange: hsl(var(--hue-orange), 90%, 60%); - --color-orange-low: hsl(var(--hue-orange), 90%, 88%); - --color-green-high: hsl(var(--hue-green), 80%, 22%); - --color-green: hsl(var(--hue-green), 90%, 46%); - --color-green-low: hsl(var(--hue-green), 85%, 90%); - --color-blue-high: hsl(var(--hue-blue), 80%, 30%); - --color-blue: hsl(var(--hue-blue), 90%, 60%); - --color-blue-low: hsl(var(--hue-blue), 88%, 90%); - --color-purple-high: hsl(var(--hue-purple), 90%, 30%); - --color-purple: hsl(var(--hue-purple), 90%, 60%); - --color-purple-low: hsl(var(--hue-purple), 80%, 90%); - --color-red-high: hsl(var(--hue-red), 80%, 30%); - --color-red: hsl(var(--hue-red), 90%, 60%); - --color-red-low: hsl(var(--hue-red), 80%, 90%); - - --color-accent-high: hsl(13, 75%, 26%); - --color-accent: hsl(13, 88%, 60%); - --color-accent-low: hsl(13, 100%, 89%); - - --color-text-accent: var(--color-accent); - --color-text-dimmed: var(--color-gray-4); - --color-text-invert: var(--color-black); - --color-text-accent-invert: var(--color-accent-low); - --color-bg-surface: var(--color-gray-6); - --color-bg-accent: var(--color-accent); - - --color-backdrop-overlay: hsla(225, 9%, 36%, 0.66); -} diff --git a/cloud/web/src/ui/style/token/font.css b/cloud/web/src/ui/style/token/font.css deleted file mode 100644 index 24b2db3f28e..00000000000 --- a/cloud/web/src/ui/style/token/font.css +++ /dev/null @@ -1,20 +0,0 @@ -:root { - --font-size-2xs: 0.6875rem; - --font-size-xs: 0.75rem; - --font-size-sm: 0.8125rem; - --font-size-md: 0.9375rem; - --font-size-lg: 1.125rem; - --font-size-xl: 1.25rem; - --font-size-2xl: 1.5rem; - --font-size-3xl: 1.875rem; - --font-size-4xl: 2.25rem; - --font-size-5xl: 3rem; - --font-size-6xl: 3.75rem; - --font-size-7xl: 4.5rem; - --font-size-8xl: 6rem; - --font-size-9xl: 8rem; - --font-mono: IBM Plex Mono, monospace; - --font-sans: Rubik, sans-serif; - - --font-line-height: 1.75; -} diff --git a/cloud/web/src/ui/style/token/reset.css b/cloud/web/src/ui/style/token/reset.css deleted file mode 100644 index f4aa1a0a9a0..00000000000 --- a/cloud/web/src/ui/style/token/reset.css +++ /dev/null @@ -1,212 +0,0 @@ -* { - margin: 0; - padding: 0; - font: inherit; -} - -*, -*::before, -*::after { - box-sizing: border-box; - border-width: 0; - border-style: solid; - border-color: var(--global-color-border, currentColor); -} - -html { - line-height: 1.5; - --font-fallback: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, - "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, - "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - -webkit-text-size-adjust: 100%; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -moz-tab-size: 4; - tab-size: 4; - font-family: var(--global-font-body, var(--font-fallback)); -} - -hr { - height: 0; - color: inherit; - border-top-width: 1px; -} - -body { - height: 100%; - line-height: inherit; -} - -img { - border-style: none; -} - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - vertical-align: middle; -} - -img, -video { - max-width: 100%; - height: auto; -} - -p, -h1, -h2, -h3, -h4, -h5, -h6 { - overflow-wrap: break-word; -} - -ol, -ul { - list-style: none; -} - -code, -kbd, -pre, -samp { - font-size: 1em; -} - -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; - background-color: transparent; - background-image: none; -} - -button, -input, -optgroup, -select, -textarea { - color: inherit; -} - -button, -select { - text-transform: none; -} - -table { - text-indent: 0; - border-color: inherit; - border-collapse: collapse; -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - color: var(--global-color-placeholder, #9ca3af); -} - -textarea { - resize: vertical; -} - -summary { - display: list-item; -} - -small { - font-size: 80%; -} - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -dialog { - padding: 0; -} - -a { - color: inherit; - text-decoration: inherit; -} - -abbr:where([title]) { - text-decoration: underline dotted; -} - -b, -strong { - font-weight: bolder; -} - -code, -kbd, -samp, -pre { - font-size: 1em; - --font-mono-fallback: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - "Liberation Mono", "Courier New"; - font-family: var(--global-font-mono, var(--font-fallback)); -} - -input[type="text"], -input[type="email"], -input[type="search"], -input[type="password"] { - -webkit-appearance: none; - -moz-appearance: none; -} - -input[type="search"] { - -webkit-appearance: textfield; - outline-offset: -2px; -} - -::-webkit-search-decoration, -::-webkit-search-cancel-button { - -webkit-appearance: none; -} - -::-webkit-file-upload-button { - -webkit-appearance: button; - font: inherit; -} - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -input[type="number"] { - -moz-appearance: textfield; -} - -:-moz-ui-invalid { - box-shadow: none; -} - -:-moz-focusring { - outline: auto; -} diff --git a/cloud/web/src/ui/style/token/space.css b/cloud/web/src/ui/style/token/space.css deleted file mode 100644 index 4a061d7561f..00000000000 --- a/cloud/web/src/ui/style/token/space.css +++ /dev/null @@ -1,39 +0,0 @@ -:root { - --space-0: 0; - --space-px: 1px; - --space-0-5: 0.125rem; - --space-1: 0.25rem; - --space-1-5: 0.375rem; - --space-2: 0.5rem; - --space-2-5: 0.625rem; - --space-3: 0.75rem; - --space-3-5: 0.875rem; - --space-4: 1rem; - --space-4-5: 1.125rem; - --space-5: 1.25rem; - --space-6: 1.5rem; - --space-7: 1.75rem; - --space-8: 2rem; - --space-9: 2.25rem; - --space-10: 2.5rem; - --space-11: 2.75rem; - --space-12: 3rem; - --space-14: 3.5rem; - --space-16: 4rem; - --space-18: 4.5rem; - --space-20: 5rem; - --space-24: 6rem; - --space-28: 7rem; - --space-32: 8rem; - --space-36: 9rem; - --space-40: 10rem; - --space-44: 11rem; - --space-48: 12rem; - --space-52: 13rem; - --space-56: 14rem; - --space-60: 15rem; - --space-64: 16rem; - --space-72: 18rem; - --space-80: 20rem; - --space-96: 24rem; -} diff --git a/cloud/web/src/ui/svg/icons.tsx b/cloud/web/src/ui/svg/icons.tsx deleted file mode 100644 index c09bbc47ad2..00000000000 --- a/cloud/web/src/ui/svg/icons.tsx +++ /dev/null @@ -1,1292 +0,0 @@ -import { JSX } from "solid-js" - -export function IconPencilSquare(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconHome(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconPlus(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconDocument(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconChat(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconBell(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconCheck(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconChevronDown(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconChevronUp(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconChevronLeft(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconChevronRight(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconTrash(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconUser(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconCog(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconExclamationCircle( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconInformationCircle( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconArrowPath(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowUpRight(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconEllipsisVertical( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconEllipsisHorizontal( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconXMark(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconAcademicCap(props: JSX.SvgSVGAttributes) { - return ( - - - - - - ) -} - -export function IconBolt(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconCalendar(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconCamera(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconClock(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconCloud(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconCreditCard(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconEnvelope(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconEye(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconFlag(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconFolder(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconGlobe(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconHeart(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconKey(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconLink(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconLock(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconMap(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconMicrophone(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconPhone(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconPhoto(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconQuestionMarkCircle( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconMagnifyingGlass( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconShieldCheck(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconShoppingCart(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconStar(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconTag(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconUserCircle(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconVideoCamera(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconWifi(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconAdjustmentsVertical( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconArchiveBox(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconArrowDown(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowLeft(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowLongDown(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowLongLeft(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowLongRight(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowLongUp(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowRight(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowSmallDown(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconArrowSmallLeft(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconArrowSmallRight( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - - ) -} - -export function IconArrowSmallUp(props: JSX.SvgSVGAttributes) { - return ( - - - - - ) -} - -export function IconArrowTopRightOnSquare( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconArrowTrendingDown( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - - ) -} - -export function IconArrowTrendingUp( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconArrowUp(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowUpCircle(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowUpLeft(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowUpOnSquare( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - - ) -} - -export function IconArrowUpTray(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconArrowsPointingIn( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconArrowsPointingOut( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconArrowsRightLeft( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} - -export function IconBars3BottomLeft( - props: JSX.SvgSVGAttributes, -) { - return ( - - - - ) -} diff --git a/cloud/web/src/ui/svg/index.tsx b/cloud/web/src/ui/svg/index.tsx deleted file mode 100644 index 23dd74c6e24..00000000000 --- a/cloud/web/src/ui/svg/index.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { JSX } from "solid-js" - -export function IconLogomark(props: JSX.SvgSVGAttributes) { - return ( - - - - ) -} - -export function IconLogo(props: JSX.SvgSVGAttributes) { - return ( - - - - - - - - - - - - - - - ) -} diff --git a/cloud/web/src/util/context.tsx b/cloud/web/src/util/context.tsx deleted file mode 100644 index d1c6f4e7f73..00000000000 --- a/cloud/web/src/util/context.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { ParentProps, Show, createContext, useContext } from "solid-js" - -export function createInitializedContext< - Name extends string, - T extends { ready: boolean }, ->(name: Name, cb: () => T) { - const ctx = createContext() - - return { - use: () => { - const context = useContext(ctx) - if (!context) throw new Error(`No ${name} context`) - return context - }, - provider: (props: ParentProps) => { - const value = cb() - return ( - - - {props.children} - - - ) - }, - } -} diff --git a/cloud/web/tsconfig.json b/cloud/web/tsconfig.json deleted file mode 100644 index 98d5b9cea0a..00000000000 --- a/cloud/web/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@tsconfig/node22/tsconfig.json", - "compilerOptions": { - "jsx": "preserve", - "jsxImportSource": "solid-js", - "module": "esnext", - "moduleResolution": "bundler", - "lib": ["ESNext", "DOM", "DOM.Iterable"], - "types": ["vite/client"] - } -} diff --git a/cloud/web/vite.config.ts b/cloud/web/vite.config.ts deleted file mode 100644 index 8a569641ed0..00000000000 --- a/cloud/web/vite.config.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { defineConfig } from "vite" -import solidPlugin from "vite-plugin-solid" -import pages from "vite-plugin-pages" -import fs from "fs" -import path from "path" -import { generateHydrationScript, getAssets } from "solid-js/web" - -export default defineConfig({ - plugins: [ - pages({ - exclude: ["**/~*", "**/components/*"], - }), - solidPlugin({ ssr: true }), - { - name: "vite-plugin-solid-ssr-render", - apply: (config, env) => { - return env.command === "build" && !config.build?.ssr - }, - closeBundle: async () => { - console.log("Pre-rendering pages...") - const dist = path.resolve("dist") - try { - const serverEntryPath = path.join(dist, "server/entry-server.js") - const serverEntry = await import(serverEntryPath + "?t=" + Date.now()) - - const template = fs.readFileSync( - path.join(dist, "client/index.html"), - "utf-8", - ) - fs.writeFileSync(path.join(dist, "client/fallback.html"), template) - - const routes = ["/"] - for (const route of routes) { - const { app } = await serverEntry.render({ url: route }) - const html = template - .replace("", app) - .replace("", generateHydrationScript()) - .replace("", getAssets()) - const filePath = path.join( - dist, - `client${route === "/" ? "/index" : route}.html`, - ) - fs.mkdirSync(path.dirname(filePath), { - recursive: true, - }) - fs.writeFileSync(filePath, html) - - console.log(`Pre-rendered: ${filePath}`) - } - } catch (error) { - console.error("Error during pre-rendering:", error) - } - }, - }, - ], - server: { - port: 3000, - host: "0.0.0.0", - }, - build: { - target: "esnext", - }, -}) diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000000..16fb71c0a5a --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1768393167, + "narHash": "sha256-n2063BRjHde6DqAz2zavhOOiLUwA3qXt7jQYHyETjX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2f594d5af95d4fdac67fba60376ec11e482041cb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000000..e4d214a0b93 --- /dev/null +++ b/flake.nix @@ -0,0 +1,69 @@ +{ + description = "OpenCode development flake"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + }; + + outputs = + { self, nixpkgs, ... }: + let + systems = [ + "aarch64-linux" + "x86_64-linux" + "aarch64-darwin" + "x86_64-darwin" + ]; + forEachSystem = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system}); + rev = self.shortRev or self.dirtyShortRev or "dirty"; + in + { + devShells = forEachSystem (pkgs: { + default = pkgs.mkShell { + packages = with pkgs; [ + bun + nodejs_20 + pkg-config + openssl + git + ]; + }; + }); + + packages = forEachSystem ( + pkgs: + let + node_modules = pkgs.callPackage ./nix/node_modules.nix { + inherit rev; + }; + opencode = pkgs.callPackage ./nix/opencode.nix { + inherit node_modules; + }; + desktop = pkgs.callPackage ./nix/desktop.nix { + inherit opencode; + }; + # nixpkgs cpu naming to bun cpu naming + cpuMap = { x86_64 = "x64"; aarch64 = "arm64"; }; + # matrix of node_modules builds - these will always fail due to fakeHash usage + # but allow computation of the correct hash from any build machine for any cpu/os + # see the update-nix-hashes workflow for usage + moduleUpdaters = pkgs.lib.listToAttrs ( + pkgs.lib.concatMap (cpu: + map (os: { + name = "${cpu}-${os}_node_modules"; + value = node_modules.override { + bunCpu = cpuMap.${cpu}; + bunOs = os; + hash = pkgs.lib.fakeHash; + }; + }) [ "linux" "darwin" ] + ) [ "x86_64" "aarch64" ] + ); + in + { + default = opencode; + inherit opencode desktop; + } // moduleUpdaters + ); + }; +} diff --git a/github/README.md b/github/README.md index 7601f51335b..17b24ffb1d6 100644 --- a/github/README.md +++ b/github/README.md @@ -6,7 +6,7 @@ Mention `/opencode` in your comment, and opencode will execute tasks within your ## Features -#### Explain an issues +#### Explain an issue Leave the following comment on a GitHub issue. `opencode` will read the entire thread, including all comments, and reply with a clear explanation. @@ -14,7 +14,7 @@ Leave the following comment on a GitHub issue. `opencode` will read the entire t /opencode explain this issue ``` -#### Fix an issues +#### Fix an issue Leave the following comment on a GitHub issue. opencode will create a new branch, implement the changes, and open a PR with the changes. @@ -30,6 +30,24 @@ Leave the following comment on a GitHub PR. opencode will implement the requeste Delete the attachment from S3 when the note is removed /oc ``` +#### Review specific code lines + +Leave a comment directly on code lines in the PR's "Files" tab. opencode will automatically detect the file, line numbers, and diff context to provide precise responses. + +``` +[Comment on specific lines in Files tab] +/oc add error handling here +``` + +When commenting on specific lines, opencode receives: + +- The exact file being reviewed +- The specific lines of code +- The surrounding diff context +- Line number information + +This allows for more targeted requests without needing to specify file paths or line numbers manually. + ## Installation Run the following command in the terminal from your GitHub repo: @@ -51,6 +69,8 @@ This will walk you through installing the GitHub app, creating the workflow, and on: issue_comment: types: [created] + pull_request_review_comment: + types: [created] jobs: opencode: @@ -61,24 +81,27 @@ This will walk you through installing the GitHub app, creating the workflow, and permissions: id-token: write steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run opencode - uses: sst/opencode/github@latest + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Run opencode + uses: anomalyco/opencode/github@latest env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: model: anthropic/claude-sonnet-4-20250514 + use_github_token: true ``` 3. Store the API keys in secrets. In your organization or project **settings**, expand **Secrets and variables** on the left and select **Actions**. Add the required API keys. ## Support -This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/sst/opencode/issues. +This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/anomalyco/opencode/issues. ## Development @@ -104,7 +127,7 @@ To test locally: - `MODEL`: The model used by opencode. Same as the `MODEL` defined in the GitHub workflow. - `ANTHROPIC_API_KEY`: Your model provider API key. Same as the keys defined in the GitHub workflow. - `GITHUB_RUN_ID`: Dummy value to emulate GitHub action environment. - - `MOCK_TOKEN`: A GitHub persontal access token. This token is used to verify you have `admin` or `write` access to the test repo. Generate a token [here](https://github.com/settings/personal-access-tokens). + - `MOCK_TOKEN`: A GitHub personal access token. This token is used to verify you have `admin` or `write` access to the test repo. Generate a token [here](https://github.com/settings/personal-access-tokens). - `MOCK_EVENT`: Mock GitHub event payload (see templates below). - `/path/to/opencode`: Path to your cloned opencode repo. `bun /path/to/opencode/github/index.ts` runs your local version of `opencode`. @@ -118,7 +141,7 @@ Replace: - `"owner":"sst"` with repo owner - `"repo":"hello-world"` with repo name -- `"actor":"fwang"` with the GitHub username of commentor +- `"actor":"fwang"` with the GitHub username of commenter - `"number":4` with the GitHub issue id - `"body":"hey opencode, summarize thread"` with comment body @@ -135,3 +158,9 @@ Replace the image URL `https://github.com/user-attachments/assets/xxxxxxxx` with ``` MOCK_EVENT='{"eventName":"issue_comment","repo":{"owner":"sst","repo":"hello-world"},"actor":"fwang","payload":{"issue":{"number":4,"pull_request":{}},"comment":{"id":1,"body":"hey opencode, summarize thread"}}}' ``` + +### PR review comment event + +``` +MOCK_EVENT='{"eventName":"pull_request_review_comment","repo":{"owner":"sst","repo":"hello-world"},"actor":"fwang","payload":{"pull_request":{"number":7},"comment":{"id":1,"body":"hey opencode, add error handling","path":"src/components/Button.tsx","diff_hunk":"@@ -45,8 +45,11 @@\n- const handleClick = () => {\n- console.log('clicked')\n+ const handleClick = useCallback(() => {\n+ console.log('clicked')\n+ doSomething()\n+ }, [doSomething])","line":47,"original_line":45,"position":10,"commit_id":"abc123","original_commit_id":"def456"}}}' +``` diff --git a/github/action.yml b/github/action.yml index 9893bc80859..8652bb8c151 100644 --- a/github/action.yml +++ b/github/action.yml @@ -6,38 +6,69 @@ branding: inputs: model: - description: "The model to use with opencode. Takes the format of `provider/model`." + description: "Model to use" required: true + agent: + description: "Agent to use. Must be a primary agent. Falls back to default_agent from config or 'build' if not found." + required: false + share: - description: "Whether to share the opencode session. Defaults to true for public repositories." + description: "Share the opencode session (defaults to true for public repos)" + required: false + + prompt: + description: "Custom prompt to override the default prompt" + required: false + + use_github_token: + description: "Use GITHUB_TOKEN directly instead of OpenCode App token exchange. When true, skips OIDC and uses the GITHUB_TOKEN env var." + required: false + default: "false" + + mentions: + description: "Comma-separated list of trigger phrases (case-insensitive). Defaults to '/opencode,/oc'" required: false - token: - description: "Optional GitHub access token for performing operations such as creating comments, committing changes, and opening pull requests. Defaults to the installation access token from the opencode GitHub App." + oidc_base_url: + description: "Base URL for OIDC token exchange API. Only required when running a custom GitHub App install. Defaults to https://api.opencode.ai" required: false runs: using: "composite" steps: - - name: Install opencode + - name: Get opencode version + id: version shell: bash - run: curl -fsSL https://opencode.ai/install | bash + run: | + VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4) + echo "version=${VERSION:-latest}" >> $GITHUB_OUTPUT + + - name: Cache opencode + id: cache + uses: actions/cache@v4 + with: + path: ~/.opencode/bin + key: opencode-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }} - - name: Install bun + - name: Install opencode + if: steps.cache.outputs.cache-hit != 'true' shell: bash - run: npm install -g bun + run: curl -fsSL https://opencode.ai/install | bash - - name: Install dependencies + - name: Add opencode to PATH shell: bash - run: | - cd ${GITHUB_ACTION_PATH} - bun install + run: echo "$HOME/.opencode/bin" >> $GITHUB_PATH - name: Run opencode shell: bash - run: bun ${GITHUB_ACTION_PATH}/index.ts + id: run_opencode + run: opencode github run env: MODEL: ${{ inputs.model }} + AGENT: ${{ inputs.agent }} SHARE: ${{ inputs.share }} - TOKEN: ${{ inputs.token }} + PROMPT: ${{ inputs.prompt }} + USE_GITHUB_TOKEN: ${{ inputs.use_github_token }} + MENTIONS: ${{ inputs.mentions }} + OIDC_BASE_URL: ${{ inputs.oidc_base_url }} diff --git a/github/index.ts b/github/index.ts index 4d0e9e68ad9..73378894cd3 100644 --- a/github/index.ts +++ b/github/index.ts @@ -5,7 +5,7 @@ import { graphql } from "@octokit/graphql" import * as core from "@actions/core" import * as github from "@actions/github" import type { Context as GitHubContext } from "@actions/github/lib/context" -import type { IssueCommentEvent } from "@octokit/webhooks-types" +import type { IssueCommentEvent, PullRequestReviewCommentEvent } from "@octokit/webhooks-types" import { createOpencodeClient } from "@opencode-ai/sdk" import { spawn } from "node:child_process" @@ -124,7 +124,7 @@ let exitCode = 0 type PromptFiles = Awaited>["promptFiles"] try { - assertContextEvent("issue_comment") + assertContextEvent("issue_comment", "pull_request_review_comment") assertPayloadKeyword() await assertOpencodeConnected() @@ -152,6 +152,9 @@ try { return session.id.slice(-8) })() console.log("opencode session", session.id) + if (shareId) { + console.log("Share link:", `${useShareUrl()}/s/${shareId}`) + } // Handle 3 cases // 1. Issue @@ -238,23 +241,47 @@ function createOpencode() { } function assertPayloadKeyword() { - const payload = useContext().payload as IssueCommentEvent + const payload = useContext().payload as IssueCommentEvent | PullRequestReviewCommentEvent const body = payload.comment.body.trim() if (!body.match(/(?:^|\s)(?:\/opencode|\/oc)(?=$|\s)/)) { throw new Error("Comments must mention `/opencode` or `/oc`") } } +function getReviewCommentContext() { + const context = useContext() + if (context.eventName !== "pull_request_review_comment") { + return null + } + + const payload = context.payload as PullRequestReviewCommentEvent + return { + file: payload.comment.path, + diffHunk: payload.comment.diff_hunk, + line: payload.comment.line, + originalLine: payload.comment.original_line, + position: payload.comment.position, + commitId: payload.comment.commit_id, + originalCommitId: payload.comment.original_commit_id, + } +} + async function assertOpencodeConnected() { let retry = 0 let connected = false do { try { - await client.app.get() + await client.app.log({ + body: { + service: "github-workflow", + level: "info", + message: "Prepare to react to Github Workflow event", + }, + }) connected = true break } catch (e) {} - await new Promise((resolve) => setTimeout(resolve, 300)) + await Bun.sleep(300) } while (retry++ < 30) if (!connected) { @@ -291,6 +318,10 @@ function useEnvRunUrl() { return `/${repo.owner}/${repo.repo}/actions/runs/${runId}` } +function useEnvAgent() { + return process.env["AGENT"] || undefined +} + function useEnvShare() { const value = process.env["SHARE"] if (!value) return undefined @@ -380,11 +411,24 @@ async function createComment() { } async function getUserPrompt() { + const context = useContext() + const payload = context.payload as IssueCommentEvent | PullRequestReviewCommentEvent + const reviewContext = getReviewCommentContext() + let prompt = (() => { - const payload = useContext().payload as IssueCommentEvent const body = payload.comment.body.trim() - if (body === "/opencode" || body === "/oc") return "Summarize this thread" - if (body.includes("/opencode") || body.includes("/oc")) return body + if (body === "/opencode" || body === "/oc") { + if (reviewContext) { + return `Review this code change and suggest improvements for the commented lines:\n\nFile: ${reviewContext.file}\nLines: ${reviewContext.line}\n\n${reviewContext.diffHunk}` + } + return "Summarize this thread" + } + if (body.includes("/opencode") || body.includes("/oc")) { + if (reviewContext) { + return `${body}\n\nContext: You are reviewing a comment on file "${reviewContext.file}" at line ${reviewContext.line}.\n\nDiff context:\n${reviewContext.diffHunk}` + } + return body + } throw new Error("Comments must mention `/opencode` or `/oc`") })() @@ -530,24 +574,49 @@ async function subscribeSessionEvents() { } async function summarize(response: string) { - const payload = useContext().payload as IssueCommentEvent try { return await chat(`Summarize the following in less than 40 characters:\n\n${response}`) } catch (e) { + if (isScheduleEvent()) { + return "Scheduled task changes" + } + const payload = useContext().payload as IssueCommentEvent return `Fix issue: ${payload.issue.title}` } } +async function resolveAgent(): Promise { + const envAgent = useEnvAgent() + if (!envAgent) return undefined + + // Validate the agent exists and is a primary agent + const agents = await client.agent.list() + const agent = agents.data?.find((a) => a.name === envAgent) + + if (!agent) { + console.warn(`agent "${envAgent}" not found. Falling back to default agent`) + return undefined + } + + if (agent.mode === "subagent") { + console.warn(`agent "${envAgent}" is a subagent, not a primary agent. Falling back to default agent`) + return undefined + } + + return envAgent +} + async function chat(text: string, files: PromptFiles = []) { console.log("Sending message to opencode...") const { providerID, modelID } = useEnvModel() + const agent = await resolveAgent() const chat = await client.session.chat({ path: session, body: { providerID, modelID, - agent: "build", + agent, parts: [ { type: "text", @@ -730,12 +799,13 @@ async function updateComment(body: string) { async function createPR(base: string, branch: string, title: string, body: string) { console.log("Creating pull request...") const { repo } = useContext() + const truncatedTitle = title.length > 256 ? title.slice(0, 253) + "..." : title const pr = await octoRest.rest.pulls.create({ owner: repo.owner, repo: repo.repo, head: branch, base, - title, + title: truncatedTitle, body, }) return pr.data.number diff --git a/github/package.json b/github/package.json index 3be63d33176..e1b913abedc 100644 --- a/github/package.json +++ b/github/package.json @@ -3,8 +3,9 @@ "module": "index.ts", "type": "module", "private": true, + "license": "MIT", "devDependencies": { - "@types/bun": "latest" + "@types/bun": "catalog:" }, "peerDependencies": { "typescript": "^5" @@ -13,7 +14,7 @@ "@actions/core": "1.11.1", "@actions/github": "6.0.1", "@octokit/graphql": "9.0.1", - "@octokit/rest": "22.0.0", - "@opencode-ai/sdk": "0.5.4" + "@octokit/rest": "catalog:", + "@opencode-ai/sdk": "workspace:*" } } diff --git a/infra/app.ts b/infra/app.ts index e1e7b26c6b8..bb627f51ec5 100644 --- a/infra/app.ts +++ b/infra/app.ts @@ -2,6 +2,12 @@ import { domain } from "./stage" const GITHUB_APP_ID = new sst.Secret("GITHUB_APP_ID") const GITHUB_APP_PRIVATE_KEY = new sst.Secret("GITHUB_APP_PRIVATE_KEY") +export const EMAILOCTOPUS_API_KEY = new sst.Secret("EMAILOCTOPUS_API_KEY") +const ADMIN_SECRET = new sst.Secret("ADMIN_SECRET") +const DISCORD_SUPPORT_BOT_TOKEN = new sst.Secret("DISCORD_SUPPORT_BOT_TOKEN") +const DISCORD_SUPPORT_CHANNEL_ID = new sst.Secret("DISCORD_SUPPORT_CHANNEL_ID") +const FEISHU_APP_ID = new sst.Secret("FEISHU_APP_ID") +const FEISHU_APP_SECRET = new sst.Secret("FEISHU_APP_SECRET") const bucket = new sst.cloudflare.Bucket("Bucket") export const api = new sst.cloudflare.Worker("Api", { @@ -11,7 +17,16 @@ export const api = new sst.cloudflare.Worker("Api", { WEB_DOMAIN: domain, }, url: true, - link: [bucket, GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY], + link: [ + bucket, + GITHUB_APP_ID, + GITHUB_APP_PRIVATE_KEY, + ADMIN_SECRET, + DISCORD_SUPPORT_BOT_TOKEN, + DISCORD_SUPPORT_CHANNEL_ID, + FEISHU_APP_ID, + FEISHU_APP_SECRET, + ], transform: { worker: (args) => { args.logpush = true @@ -33,8 +48,8 @@ export const api = new sst.cloudflare.Worker("Api", { }, }) -export const web = new sst.cloudflare.x.Astro("Web", { - domain, +new sst.cloudflare.x.Astro("Web", { + domain: "docs." + domain, path: "packages/web", environment: { // For astro config @@ -42,3 +57,12 @@ export const web = new sst.cloudflare.x.Astro("Web", { VITE_API_URL: api.url.apply((url) => url!), }, }) + +new sst.cloudflare.StaticSite("WebApp", { + domain: "app." + domain, + path: "packages/app", + build: { + command: "bun turbo build", + output: "./dist", + }, +}) diff --git a/infra/cloud.ts b/infra/cloud.ts deleted file mode 100644 index d1ffb51e09c..00000000000 --- a/infra/cloud.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { WebhookEndpoint } from "pulumi-stripe" -import { domain } from "./stage" -import { web } from "./app" - -//////////////// -// DATABASE -//////////////// - -const DATABASE_USERNAME = new sst.Secret("DATABASE_USERNAME") -const DATABASE_PASSWORD = new sst.Secret("DATABASE_PASSWORD") -export const database = new sst.Linkable("Database", { - properties: { - host: `aws-us-east-2-${$app.stage === "thdxr" ? "2" : "1"}.pg.psdb.cloud`, - database: "postgres", - username: DATABASE_USERNAME.value, - password: DATABASE_PASSWORD.value, - port: 5432, - }, -}) - -new sst.x.DevCommand("Studio", { - link: [database], - dev: { - command: "bun db studio", - directory: "cloud/core", - autostart: true, - }, -}) - -//////////////// -// AUTH -//////////////// - -const GITHUB_CLIENT_ID_CONSOLE = new sst.Secret("GITHUB_CLIENT_ID_CONSOLE") -const GITHUB_CLIENT_SECRET_CONSOLE = new sst.Secret("GITHUB_CLIENT_SECRET_CONSOLE") -const GOOGLE_CLIENT_ID = new sst.Secret("GOOGLE_CLIENT_ID") -const authStorage = new sst.cloudflare.Kv("AuthStorage") -export const auth = new sst.cloudflare.Worker("AuthApi", { - domain: `auth.${domain}`, - handler: "cloud/function/src/auth.ts", - url: true, - link: [database, authStorage, GITHUB_CLIENT_ID_CONSOLE, GITHUB_CLIENT_SECRET_CONSOLE, GOOGLE_CLIENT_ID], -}) - -//////////////// -// GATEWAY -//////////////// - -export const stripeWebhook = new WebhookEndpoint("StripeWebhook", { - url: $interpolate`https://api.gateway.${domain}/stripe/webhook`, - enabledEvents: [ - "checkout.session.async_payment_failed", - "checkout.session.async_payment_succeeded", - "checkout.session.completed", - "checkout.session.expired", - "customer.created", - "customer.deleted", - "customer.updated", - "customer.discount.created", - "customer.discount.deleted", - "customer.discount.updated", - "customer.source.created", - "customer.source.deleted", - "customer.source.expiring", - "customer.source.updated", - "customer.subscription.created", - "customer.subscription.deleted", - "customer.subscription.paused", - "customer.subscription.pending_update_applied", - "customer.subscription.pending_update_expired", - "customer.subscription.resumed", - "customer.subscription.trial_will_end", - "customer.subscription.updated", - "customer.tax_id.created", - "customer.tax_id.deleted", - "customer.tax_id.updated", - ], -}) - -const ANTHROPIC_API_KEY = new sst.Secret("ANTHROPIC_API_KEY") -const OPENAI_API_KEY = new sst.Secret("OPENAI_API_KEY") -const ZHIPU_API_KEY = new sst.Secret("ZHIPU_API_KEY") -const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY") -const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", { - properties: { value: auth.url.apply((url) => url!) }, -}) -const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", { - properties: { value: stripeWebhook.secret }, -}) -export const gateway = new sst.cloudflare.Worker("GatewayApi", { - domain: `api.gateway.${domain}`, - handler: "cloud/function/src/gateway.ts", - url: true, - link: [ - database, - AUTH_API_URL, - STRIPE_WEBHOOK_SECRET, - STRIPE_SECRET_KEY, - ANTHROPIC_API_KEY, - OPENAI_API_KEY, - ZHIPU_API_KEY, - ], -}) - -//////////////// -// CONSOLE -//////////////// - -/* -export const console = new sst.cloudflare.x.StaticSite("Console", { - domain: `console.${domain}`, - path: "cloud/web", - build: { - command: "bun run build", - output: "dist/client", - }, - environment: { - VITE_DOCS_URL: web.url.apply((url) => url!), - VITE_API_URL: gateway.url.apply((url) => url!), - VITE_AUTH_URL: auth.url.apply((url) => url!), - }, -}) -*/ - -new sst.x.DevCommand("Solid", { - link: [database], - dev: { - directory: "cloud/app", - command: "bun dev", - }, - environment: { - VITE_AUTH_URL: auth.url.apply((url) => url!), - }, -}) diff --git a/infra/console.ts b/infra/console.ts new file mode 100644 index 00000000000..3d482160d02 --- /dev/null +++ b/infra/console.ts @@ -0,0 +1,205 @@ +import { domain } from "./stage" +import { EMAILOCTOPUS_API_KEY } from "./app" + +//////////////// +// DATABASE +//////////////// + +const cluster = planetscale.getDatabaseOutput({ + name: "opencode", + organization: "anomalyco", +}) + +const branch = + $app.stage === "production" + ? planetscale.getBranchOutput({ + name: "production", + organization: cluster.organization, + database: cluster.name, + }) + : new planetscale.Branch("DatabaseBranch", { + database: cluster.name, + organization: cluster.organization, + name: $app.stage, + parentBranch: "production", + }) +const password = new planetscale.Password("DatabasePassword", { + name: $app.stage, + database: cluster.name, + organization: cluster.organization, + branch: branch.name, +}) + +export const database = new sst.Linkable("Database", { + properties: { + host: password.accessHostUrl, + database: cluster.name, + username: password.username, + password: password.plaintext, + port: 3306, + }, +}) + +new sst.x.DevCommand("Studio", { + link: [database], + dev: { + command: "bun db studio", + directory: "packages/console/core", + autostart: true, + }, +}) + +//////////////// +// AUTH +//////////////// + +const GITHUB_CLIENT_ID_CONSOLE = new sst.Secret("GITHUB_CLIENT_ID_CONSOLE") +const GITHUB_CLIENT_SECRET_CONSOLE = new sst.Secret("GITHUB_CLIENT_SECRET_CONSOLE") +const GOOGLE_CLIENT_ID = new sst.Secret("GOOGLE_CLIENT_ID") +const authStorage = new sst.cloudflare.Kv("AuthStorage") +export const auth = new sst.cloudflare.Worker("AuthApi", { + domain: `auth.${domain}`, + handler: "packages/console/function/src/auth.ts", + url: true, + link: [database, authStorage, GITHUB_CLIENT_ID_CONSOLE, GITHUB_CLIENT_SECRET_CONSOLE, GOOGLE_CLIENT_ID], +}) + +//////////////// +// GATEWAY +//////////////// + +export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhookEndpoint", { + url: $interpolate`https://${domain}/stripe/webhook`, + enabledEvents: [ + "checkout.session.async_payment_failed", + "checkout.session.async_payment_succeeded", + "checkout.session.completed", + "checkout.session.expired", + "charge.refunded", + "invoice.payment_succeeded", + "customer.created", + "customer.deleted", + "customer.updated", + "customer.discount.created", + "customer.discount.deleted", + "customer.discount.updated", + "customer.source.created", + "customer.source.deleted", + "customer.source.expiring", + "customer.source.updated", + "customer.subscription.created", + "customer.subscription.deleted", + "customer.subscription.paused", + "customer.subscription.pending_update_applied", + "customer.subscription.pending_update_expired", + "customer.subscription.resumed", + "customer.subscription.trial_will_end", + "customer.subscription.updated", + ], +}) + +const zenProduct = new stripe.Product("ZenBlack", { + name: "OpenCode Black", +}) +const zenPriceProps = { + product: zenProduct.id, + currency: "usd", + recurring: { + interval: "month", + intervalCount: 1, + }, +} +const zenPrice200 = new stripe.Price("ZenBlackPrice", { ...zenPriceProps, unitAmount: 20000 }) +const zenPrice100 = new stripe.Price("ZenBlack100Price", { ...zenPriceProps, unitAmount: 10000 }) +const zenPrice20 = new stripe.Price("ZenBlack20Price", { ...zenPriceProps, unitAmount: 2000 }) +const ZEN_BLACK_PRICE = new sst.Linkable("ZEN_BLACK_PRICE", { + properties: { + product: zenProduct.id, + plan200: zenPrice200.id, + plan100: zenPrice100.id, + plan20: zenPrice20.id, + }, +}) +const ZEN_BLACK_LIMITS = new sst.Secret("ZEN_BLACK_LIMITS") + +const ZEN_MODELS = [ + new sst.Secret("ZEN_MODELS1"), + new sst.Secret("ZEN_MODELS2"), + new sst.Secret("ZEN_MODELS3"), + new sst.Secret("ZEN_MODELS4"), + new sst.Secret("ZEN_MODELS5"), + new sst.Secret("ZEN_MODELS6"), + new sst.Secret("ZEN_MODELS7"), + new sst.Secret("ZEN_MODELS8"), +] +const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY") +const STRIPE_PUBLISHABLE_KEY = new sst.Secret("STRIPE_PUBLISHABLE_KEY") +const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", { + properties: { value: auth.url.apply((url) => url!) }, +}) +const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", { + properties: { value: stripeWebhook.secret }, +}) +const gatewayKv = new sst.cloudflare.Kv("GatewayKv") + +//////////////// +// CONSOLE +//////////////// + +const bucket = new sst.cloudflare.Bucket("ZenData") +const bucketNew = new sst.cloudflare.Bucket("ZenDataNew") + +const AWS_SES_ACCESS_KEY_ID = new sst.Secret("AWS_SES_ACCESS_KEY_ID") +const AWS_SES_SECRET_ACCESS_KEY = new sst.Secret("AWS_SES_SECRET_ACCESS_KEY") + +let logProcessor +if ($app.stage === "production" || $app.stage === "frank") { + const HONEYCOMB_API_KEY = new sst.Secret("HONEYCOMB_API_KEY") + logProcessor = new sst.cloudflare.Worker("LogProcessor", { + handler: "packages/console/function/src/log-processor.ts", + link: [HONEYCOMB_API_KEY], + }) +} + +new sst.cloudflare.x.SolidStart("Console", { + domain, + path: "packages/console/app", + link: [ + bucket, + bucketNew, + database, + AUTH_API_URL, + STRIPE_WEBHOOK_SECRET, + STRIPE_SECRET_KEY, + EMAILOCTOPUS_API_KEY, + AWS_SES_ACCESS_KEY_ID, + AWS_SES_SECRET_ACCESS_KEY, + ZEN_BLACK_PRICE, + ZEN_BLACK_LIMITS, + new sst.Secret("ZEN_SESSION_SECRET"), + ...ZEN_MODELS, + ...($dev + ? [ + new sst.Secret("CLOUDFLARE_DEFAULT_ACCOUNT_ID", process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!), + new sst.Secret("CLOUDFLARE_API_TOKEN", process.env.CLOUDFLARE_API_TOKEN!), + ] + : []), + gatewayKv, + ], + environment: { + //VITE_DOCS_URL: web.url.apply((url) => url!), + //VITE_API_URL: gateway.url.apply((url) => url!), + VITE_AUTH_URL: auth.url.apply((url) => url!), + VITE_STRIPE_PUBLISHABLE_KEY: STRIPE_PUBLISHABLE_KEY.value, + }, + transform: { + server: { + transform: { + worker: { + placement: { mode: "smart" }, + tailConsumers: logProcessor ? [{ service: logProcessor.nodes.worker.scriptName }] : [], + }, + }, + }, + }, +}) diff --git a/infra/enterprise.ts b/infra/enterprise.ts new file mode 100644 index 00000000000..22b4c6f44ee --- /dev/null +++ b/infra/enterprise.ts @@ -0,0 +1,17 @@ +import { SECRET } from "./secret" +import { domain, shortDomain } from "./stage" + +const storage = new sst.cloudflare.Bucket("EnterpriseStorage") + +const teams = new sst.cloudflare.x.SolidStart("Teams", { + domain: shortDomain, + path: "packages/enterprise", + buildCommand: "bun run build:cloudflare", + environment: { + OPENCODE_STORAGE_ADAPTER: "r2", + OPENCODE_STORAGE_ACCOUNT_ID: sst.cloudflare.DEFAULT_ACCOUNT_ID, + OPENCODE_STORAGE_ACCESS_KEY_ID: SECRET.R2AccessKey.value, + OPENCODE_STORAGE_SECRET_ACCESS_KEY: SECRET.R2SecretKey.value, + OPENCODE_STORAGE_BUCKET: storage.name, + }, +}) diff --git a/infra/secret.ts b/infra/secret.ts new file mode 100644 index 00000000000..0b1870fa155 --- /dev/null +++ b/infra/secret.ts @@ -0,0 +1,4 @@ +export const SECRET = { + R2AccessKey: new sst.Secret("R2AccessKey", "unknown"), + R2SecretKey: new sst.Secret("R2SecretKey", "unknown"), +} diff --git a/infra/stage.ts b/infra/stage.ts index c1239832b75..f9a6fd75529 100644 --- a/infra/stage.ts +++ b/infra/stage.ts @@ -3,3 +3,17 @@ export const domain = (() => { if ($app.stage === "dev") return "dev.opencode.ai" return `${$app.stage}.dev.opencode.ai` })() + +export const zoneID = "430ba34c138cfb5360826c4909f99be8" + +new cloudflare.RegionalHostname("RegionalHostname", { + hostname: domain, + regionKey: "us", + zoneId: zoneID, +}) + +export const shortDomain = (() => { + if ($app.stage === "production") return "opncd.ai" + if ($app.stage === "dev") return "dev.opncd.ai" + return `${$app.stage}.dev.opncd.ai` +})() diff --git a/install b/install index b690ba31da9..22b7ca39ed7 100755 --- a/install +++ b/install @@ -2,59 +2,192 @@ set -euo pipefail APP=opencode +MUTED='\033[0;2m' RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -ORANGE='\033[38;2;255;140;0m' +ORANGE='\033[38;5;214m' NC='\033[0m' # No Color -requested_version=${VERSION:-} +usage() { + cat < Install a specific version (e.g., 1.0.180) + -b, --binary Install from a local binary instead of downloading + --no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.) -filename="$APP-$os-$arch.zip" +Examples: + curl -fsSL https://opencode.ai/install | bash + curl -fsSL https://opencode.ai/install | bash -s -- --version 1.0.180 + ./install --binary /path/to/opencode +EOF +} +requested_version=${VERSION:-} +no_modify_path=false +binary_path="" -case "$filename" in - *"-linux-"*) - [[ "$arch" == "x64" || "$arch" == "arm64" ]] || exit 1 - ;; - *"-darwin-"*) - [[ "$arch" == "x64" || "$arch" == "arm64" ]] || exit 1 - ;; - *"-windows-"*) - [[ "$arch" == "x64" ]] || exit 1 - ;; - *) - echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}" - exit 1 - ;; -esac +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + -v|--version) + if [[ -n "${2:-}" ]]; then + requested_version="$2" + shift 2 + else + echo -e "${RED}Error: --version requires a version argument${NC}" + exit 1 + fi + ;; + -b|--binary) + if [[ -n "${2:-}" ]]; then + binary_path="$2" + shift 2 + else + echo -e "${RED}Error: --binary requires a path argument${NC}" + exit 1 + fi + ;; + --no-modify-path) + no_modify_path=true + shift + ;; + *) + echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2 + shift + ;; + esac +done INSTALL_DIR=$HOME/.opencode/bin mkdir -p "$INSTALL_DIR" -if [ -z "$requested_version" ]; then - url="https://github.com/sst/opencode/releases/latest/download/$filename" - specific_version=$(curl -s https://api.github.com/repos/sst/opencode/releases/latest | awk -F'"' '/"tag_name": "/ {gsub(/^v/, "", $4); print $4}') - - if [[ $? -ne 0 || -z "$specific_version" ]]; then - echo -e "${RED}Failed to fetch version information${NC}" +# If --binary is provided, skip all download/detection logic +if [ -n "$binary_path" ]; then + if [ ! -f "$binary_path" ]; then + echo -e "${RED}Error: Binary not found at ${binary_path}${NC}" exit 1 fi + specific_version="local" else - url="https://github.com/sst/opencode/releases/download/v${requested_version}/$filename" - specific_version=$requested_version + raw_os=$(uname -s) + os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]') + case "$raw_os" in + Darwin*) os="darwin" ;; + Linux*) os="linux" ;; + MINGW*|MSYS*|CYGWIN*) os="windows" ;; + esac + + arch=$(uname -m) + if [[ "$arch" == "aarch64" ]]; then + arch="arm64" + fi + if [[ "$arch" == "x86_64" ]]; then + arch="x64" + fi + + if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then + rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0) + if [ "$rosetta_flag" = "1" ]; then + arch="arm64" + fi + fi + + combo="$os-$arch" + case "$combo" in + linux-x64|linux-arm64|darwin-x64|darwin-arm64|windows-x64) + ;; + *) + echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}" + exit 1 + ;; + esac + + archive_ext=".zip" + if [ "$os" = "linux" ]; then + archive_ext=".tar.gz" + fi + + is_musl=false + if [ "$os" = "linux" ]; then + if [ -f /etc/alpine-release ]; then + is_musl=true + fi + + if command -v ldd >/dev/null 2>&1; then + if ldd --version 2>&1 | grep -qi musl; then + is_musl=true + fi + fi + fi + + needs_baseline=false + if [ "$arch" = "x64" ]; then + if [ "$os" = "linux" ]; then + if ! grep -qi avx2 /proc/cpuinfo 2>/dev/null; then + needs_baseline=true + fi + fi + + if [ "$os" = "darwin" ]; then + avx2=$(sysctl -n hw.optional.avx2_0 2>/dev/null || echo 0) + if [ "$avx2" != "1" ]; then + needs_baseline=true + fi + fi + fi + + target="$os-$arch" + if [ "$needs_baseline" = "true" ]; then + target="$target-baseline" + fi + if [ "$is_musl" = "true" ]; then + target="$target-musl" + fi + + filename="$APP-$target$archive_ext" + + + if [ "$os" = "linux" ]; then + if ! command -v tar >/dev/null 2>&1; then + echo -e "${RED}Error: 'tar' is required but not installed.${NC}" + exit 1 + fi + else + if ! command -v unzip >/dev/null 2>&1; then + echo -e "${RED}Error: 'unzip' is required but not installed.${NC}" + exit 1 + fi + fi + + if [ -z "$requested_version" ]; then + url="https://github.com/anomalyco/opencode/releases/latest/download/$filename" + specific_version=$(curl -s https://api.github.com/repos/anomalyco/opencode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') + + if [[ $? -ne 0 || -z "$specific_version" ]]; then + echo -e "${RED}Failed to fetch version information${NC}" + exit 1 + fi + else + # Strip leading 'v' if present + requested_version="${requested_version#v}" + url="https://github.com/anomalyco/opencode/releases/download/v${requested_version}/$filename" + specific_version=$requested_version + + # Verify the release exists before downloading + http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/anomalyco/opencode/releases/tag/v${requested_version}") + if [ "$http_status" = "404" ]; then + echo -e "${RED}Error: Release v${requested_version} not found${NC}" + echo -e "${MUTED}Available releases: https://github.com/anomalyco/opencode/releases${NC}" + exit 1 + fi + fi fi print_message() { @@ -63,8 +196,8 @@ print_message() { local color="" case $level in - info) color="${GREEN}" ;; - warning) color="${YELLOW}" ;; + info) color="${NC}" ;; + warning) color="${NC}" ;; error) color="${RED}" ;; esac @@ -75,32 +208,141 @@ check_version() { if command -v opencode >/dev/null 2>&1; then opencode_path=$(which opencode) - - ## TODO: check if version is installed - # installed_version=$(opencode version) - installed_version="0.0.1" - installed_version=$(echo $installed_version | awk '{print $2}') + ## Check the installed version + installed_version=$(opencode --version 2>/dev/null || echo "") if [[ "$installed_version" != "$specific_version" ]]; then - print_message info "Installed version: ${YELLOW}$installed_version." + print_message info "${MUTED}Installed version: ${NC}$installed_version." else - print_message info "Version ${YELLOW}$specific_version${GREEN} already installed" + print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed" exit 0 fi fi } +unbuffered_sed() { + if echo | sed -u -e "" >/dev/null 2>&1; then + sed -nu "$@" + elif echo | sed -l -e "" >/dev/null 2>&1; then + sed -nl "$@" + else + local pad="$(printf "\n%512s" "")" + sed -ne "s/$/\\${pad}/" "$@" + fi +} + +print_progress() { + local bytes="$1" + local length="$2" + [ "$length" -gt 0 ] || return 0 + + local width=50 + local percent=$(( bytes * 100 / length )) + [ "$percent" -gt 100 ] && percent=100 + local on=$(( percent * width / 100 )) + local off=$(( width - on )) + + local filled=$(printf "%*s" "$on" "") + filled=${filled// /■} + local empty=$(printf "%*s" "$off" "") + empty=${empty// /・} + + printf "\r${ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4 +} + +download_with_progress() { + local url="$1" + local output="$2" + + if [ -t 2 ]; then + exec 4>&2 + else + exec 4>/dev/null + fi + + local tmp_dir=${TMPDIR:-/tmp} + local basename="${tmp_dir}/opencode_install_$$" + local tracefile="${basename}.trace" + + rm -f "$tracefile" + mkfifo "$tracefile" + + # Hide cursor + printf "\033[?25l" >&4 + + trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN + + ( + curl --trace-ascii "$tracefile" -s -L -o "$output" "$url" + ) & + local curl_pid=$! + + unbuffered_sed \ + -e 'y/ACDEGHLNORTV/acdeghlnortv/' \ + -e '/^0000: content-length:/p' \ + -e '/^<= recv data/p' \ + "$tracefile" | \ + { + local length=0 + local bytes=0 + + while IFS=" " read -r -a line; do + [ "${#line[@]}" -lt 2 ] && continue + local tag="${line[0]} ${line[1]}" + + if [ "$tag" = "0000: content-length:" ]; then + length="${line[2]}" + length=$(echo "$length" | tr -d '\r') + bytes=0 + elif [ "$tag" = "<= recv" ]; then + local size="${line[3]}" + bytes=$(( bytes + size )) + if [ "$length" -gt 0 ]; then + print_progress "$bytes" "$length" + fi + fi + done + } + + wait $curl_pid + local ret=$? + echo "" >&4 + return $ret +} + download_and_install() { - print_message info "Downloading ${ORANGE}opencode ${GREEN}version: ${YELLOW}$specific_version ${GREEN}..." - mkdir -p opencodetmp && cd opencodetmp - curl -# -L -o "$filename" "$url" - unzip -q "$filename" - mv opencode "$INSTALL_DIR" - cd .. && rm -rf opencodetmp + print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version" + local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$" + mkdir -p "$tmp_dir" + + if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then + # Fallback to standard curl on Windows, non-TTY environments, or if custom progress fails + curl -# -L -o "$tmp_dir/$filename" "$url" + fi + + if [ "$os" = "linux" ]; then + tar -xzf "$tmp_dir/$filename" -C "$tmp_dir" + else + unzip -q "$tmp_dir/$filename" -d "$tmp_dir" + fi + + mv "$tmp_dir/opencode" "$INSTALL_DIR" + chmod 755 "${INSTALL_DIR}/opencode" + rm -rf "$tmp_dir" } -check_version -download_and_install +install_from_binary() { + print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}from: ${NC}$binary_path" + cp "$binary_path" "${INSTALL_DIR}/opencode" + chmod 755 "${INSTALL_DIR}/opencode" +} + +if [ -n "$binary_path" ]; then + install_from_binary +else + check_version + download_and_install +fi add_to_path() { @@ -112,7 +354,7 @@ add_to_path() { elif [[ -w $config_file ]]; then echo -e "\n# opencode" >> "$config_file" echo "$command" >> "$config_file" - print_message info "Successfully added ${ORANGE}opencode ${GREEN}to \$PATH in $config_file" + print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file" else print_message warning "Manually add the directory to $config_file (or similar):" print_message info " $command" @@ -127,7 +369,7 @@ case $current_shell in config_files="$HOME/.config/fish/config.fish" ;; zsh) - config_files="$HOME/.zshrc $HOME/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv" + config_files="${ZDOTDIR:-$HOME}/.zshrc ${ZDOTDIR:-$HOME}/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv" ;; bash) config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile" @@ -144,45 +386,61 @@ case $current_shell in ;; esac -config_file="" -for file in $config_files; do - if [[ -f $file ]]; then - config_file=$file - break - fi -done - -if [[ -z $config_file ]]; then - print_message error "No config file found for $current_shell. Checked files: ${config_files[@]}" - exit 1 -fi +if [[ "$no_modify_path" != "true" ]]; then + config_file="" + for file in $config_files; do + if [[ -f $file ]]; then + config_file=$file + break + fi + done -if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then - case $current_shell in - fish) - add_to_path "$config_file" "fish_add_path $INSTALL_DIR" - ;; - zsh) - add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" - ;; - bash) - add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" - ;; - ash) - add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" - ;; - sh) - add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" - ;; - *) - export PATH=$INSTALL_DIR:$PATH - print_message warning "Manually add the directory to $config_file (or similar):" - print_message info " export PATH=$INSTALL_DIR:\$PATH" - ;; - esac + if [[ -z $config_file ]]; then + print_message warning "No config file found for $current_shell. You may need to manually add to PATH:" + print_message info " export PATH=$INSTALL_DIR:\$PATH" + elif [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then + case $current_shell in + fish) + add_to_path "$config_file" "fish_add_path $INSTALL_DIR" + ;; + zsh) + add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" + ;; + bash) + add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" + ;; + ash) + add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" + ;; + sh) + add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" + ;; + *) + export PATH=$INSTALL_DIR:$PATH + print_message warning "Manually add the directory to $config_file (or similar):" + print_message info " export PATH=$INSTALL_DIR:\$PATH" + ;; + esac + fi fi if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then echo "$INSTALL_DIR" >> $GITHUB_PATH print_message info "Added $INSTALL_DIR to \$GITHUB_PATH" fi + +echo -e "" +echo -e "${MUTED}  ${NC} ▄ " +echo -e "${MUTED}█▀▀█ █▀▀█ █▀▀█ █▀▀▄ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█" +echo -e "${MUTED}█░░█ █░░█ █▀▀▀ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀" +echo -e "${MUTED}▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀" +echo -e "" +echo -e "" +echo -e "${MUTED}OpenCode includes free models, to start:${NC}" +echo -e "" +echo -e "cd ${MUTED}# Open directory${NC}" +echo -e "opencode ${MUTED}# Run command${NC}" +echo -e "" +echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs" +echo -e "" +echo -e "" diff --git a/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json b/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json new file mode 100644 index 00000000000..41cb01a2b83 --- /dev/null +++ b/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json @@ -0,0 +1,15 @@ +{ + "keep": { + "days": true, + "amount": 14 + }, + "auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json", + "files": [ + { + "date": 1759827172859, + "name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log", + "hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16" + } + ], + "hashType": "sha256" +} diff --git a/logs/mcp-puppeteer-2025-10-07.log b/logs/mcp-puppeteer-2025-10-07.log new file mode 100644 index 00000000000..77053569666 --- /dev/null +++ b/logs/mcp-puppeteer-2025-10-07.log @@ -0,0 +1,48 @@ +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:52:52.879"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:52:52.880"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:52:56.191"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:52:56.192"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:52:59.267"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:52:59.268"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:20.276"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:20.277"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:30.838"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:30.839"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:42.452"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:42.452"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:46.499"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:53:46.500"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:54:02.295"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:54:02.295"} +{"arguments":{"url":"https://google.com"},"level":"debug","message":"Tool call received","service":"mcp-puppeteer","timestamp":"2025-10-07 04:54:37.150","tool":"puppeteer_navigate"} +{"0":"n","1":"p","2":"x","level":"info","message":"Launching browser with config:","service":"mcp-puppeteer","timestamp":"2025-10-07 04:54:37.150"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 04:55:08.488"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 04:55:08.489"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:11.815"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:11.816"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:21.934"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:21.935"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:32.544"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:32.544"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:41.154"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:41.155"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:55.426"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:23:55.427"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:24:15.715"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:24:15.716"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:24:25.063"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:24:25.064"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:24:48.567"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:24:48.568"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 05:25:08.937"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 05:25:08.938"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 22:38:37.120"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 22:38:37.121"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 22:38:52.490"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 22:38:52.491"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 22:39:25.524"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 22:39:25.525"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 22:40:57.126"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 22:40:57.127"} +{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-10-07 22:42:24.175"} +{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-10-07 22:42:24.176"} diff --git a/nix/desktop.nix b/nix/desktop.nix new file mode 100644 index 00000000000..9625f75c271 --- /dev/null +++ b/nix/desktop.nix @@ -0,0 +1,100 @@ +{ + lib, + stdenv, + rustPlatform, + pkg-config, + cargo-tauri, + bun, + nodejs, + cargo, + rustc, + jq, + wrapGAppsHook4, + makeWrapper, + dbus, + glib, + gtk4, + libsoup_3, + librsvg, + libappindicator, + glib-networking, + openssl, + webkitgtk_4_1, + gst_all_1, + opencode, +}: +rustPlatform.buildRustPackage (finalAttrs: { + pname = "opencode-desktop"; + inherit (opencode) + version + src + node_modules + patches + ; + + cargoRoot = "packages/desktop/src-tauri"; + cargoLock.lockFile = ../packages/desktop/src-tauri/Cargo.lock; + buildAndTestSubdir = finalAttrs.cargoRoot; + + nativeBuildInputs = [ + pkg-config + cargo-tauri.hook + bun + nodejs # for patchShebangs node_modules + cargo + rustc + jq + makeWrapper + ] + ++ lib.optionals stdenv.hostPlatform.isLinux [ wrapGAppsHook4 ]; + + buildInputs = lib.optionals stdenv.isLinux [ + dbus + glib + gtk4 + libsoup_3 + librsvg + libappindicator + glib-networking + openssl + webkitgtk_4_1 + gst_all_1.gstreamer + gst_all_1.gst-plugins-base + gst_all_1.gst-plugins-good + ]; + + strictDeps = true; + + preBuild = '' + cp -a ${finalAttrs.node_modules}/{node_modules,packages} . + chmod -R u+w node_modules packages + patchShebangs node_modules + patchShebangs packages/desktop/node_modules + + mkdir -p packages/desktop/src-tauri/sidecars + cp ${opencode}/bin/opencode packages/desktop/src-tauri/sidecars/opencode-cli-${stdenv.hostPlatform.rust.rustcTarget} + ''; + + # see publish-tauri job in .github/workflows/publish.yml + tauriBuildFlags = [ + "--config" + "tauri.prod.conf.json" + "--no-sign" # no code signing or auto updates + ]; + + # FIXME: workaround for concerns about case insensitive filesystems + # should be removed once binary is renamed or decided otherwise + # darwin output is a .app bundle so no conflict + postFixup = lib.optionalString stdenv.hostPlatform.isLinux '' + mv $out/bin/OpenCode $out/bin/opencode-desktop + sed -i 's|^Exec=OpenCode$|Exec=opencode-desktop|' $out/share/applications/OpenCode.desktop + ''; + + meta = { + description = "OpenCode Desktop App"; + homepage = "https://opencode.ai"; + license = lib.licenses.mit; + mainProgram = "opencode-desktop"; + inherit (opencode.meta) platforms; + }; +}) \ No newline at end of file diff --git a/nix/hashes.json b/nix/hashes.json new file mode 100644 index 00000000000..c94a408f0b8 --- /dev/null +++ b/nix/hashes.json @@ -0,0 +1,8 @@ +{ + "nodeModules": { + "x86_64-linux": "sha256-sH6zUk9G4vC6btPZIR9aiSHX0F4aGyUZB7fKbpDUcpE=", + "aarch64-linux": "sha256-CVpdXnFns34hmGwwlRrrI6Uk6B/jZUxfnH4HC2NanEo=", + "aarch64-darwin": "sha256-khP27Iiq+FAZRlzUy7rGXc2MviZjirFH1ShRyd7q1bY=", + "x86_64-darwin": "sha256-nE2p62Tld64sQVMq7j0YNT5Zwjqp22H997+K8xfi1ag=" + } +} diff --git a/nix/node_modules.nix b/nix/node_modules.nix new file mode 100644 index 00000000000..981a60ef9ba --- /dev/null +++ b/nix/node_modules.nix @@ -0,0 +1,85 @@ +{ + lib, + stdenvNoCC, + bun, + bunCpu ? if stdenvNoCC.hostPlatform.isAarch64 then "arm64" else "x64", + bunOs ? if stdenvNoCC.hostPlatform.isLinux then "linux" else "darwin", + rev ? "dirty", + hash ? + (lib.pipe ./hashes.json [ + builtins.readFile + builtins.fromJSON + ]).nodeModules.${stdenvNoCC.hostPlatform.system}, +}: +let + packageJson = lib.pipe ../packages/opencode/package.json [ + builtins.readFile + builtins.fromJSON + ]; +in +stdenvNoCC.mkDerivation { + pname = "opencode-node_modules"; + version = "${packageJson.version}-${rev}"; + + src = lib.fileset.toSource { + root = ../.; + fileset = lib.fileset.intersection (lib.fileset.fromSource (lib.sources.cleanSource ../.)) ( + lib.fileset.unions [ + ../packages + ../bun.lock + ../package.json + ../patches + ../install + ] + ); + }; + + impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ + "GIT_PROXY_COMMAND" + "SOCKS_SERVER" + ]; + + nativeBuildInputs = [ + bun + ]; + + dontConfigure = true; + + buildPhase = '' + runHook preBuild + export HOME=$(mktemp -d) + export BUN_INSTALL_CACHE_DIR=$(mktemp -d) + bun install \ + --cpu="${bunCpu}" \ + --os="${bunOs}" \ + --frozen-lockfile \ + --ignore-scripts \ + --no-progress \ + --linker=isolated + bun --bun ${./scripts/canonicalize-node-modules.ts} + bun --bun ${./scripts/normalize-bun-binaries.ts} + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out + find . -type d -name node_modules -exec cp -R --parents {} $out \; + + runHook postInstall + ''; + + dontFixup = true; + + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + outputHash = hash; + + meta.platforms = [ + "aarch64-linux" + "x86_64-linux" + "aarch64-darwin" + "x86_64-darwin" + ]; +} diff --git a/nix/opencode.nix b/nix/opencode.nix new file mode 100644 index 00000000000..23d9fbe34e0 --- /dev/null +++ b/nix/opencode.nix @@ -0,0 +1,96 @@ +{ + lib, + stdenvNoCC, + callPackage, + bun, + sysctl, + makeBinaryWrapper, + models-dev, + ripgrep, + installShellFiles, + versionCheckHook, + writableTmpDirAsHomeHook, + node_modules ? callPackage ./node-modules.nix { }, +}: +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "opencode"; + inherit (node_modules) version src; + inherit node_modules; + + nativeBuildInputs = [ + bun + installShellFiles + makeBinaryWrapper + models-dev + writableTmpDirAsHomeHook + ]; + + configurePhase = '' + runHook preConfigure + + cp -R ${finalAttrs.node_modules}/. . + + runHook postConfigure + ''; + + env.MODELS_DEV_API_JSON = "${models-dev}/dist/_api.json"; + env.OPENCODE_VERSION = finalAttrs.version; + env.OPENCODE_CHANNEL = "local"; + + buildPhase = '' + runHook preBuild + + cd ./packages/opencode + bun --bun ./script/build.ts --single --skip-install + bun --bun ./script/schema.ts schema.json + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode + install -Dm644 schema.json $out/share/opencode/schema.json + + wrapProgram $out/bin/opencode \ + --prefix PATH : ${ + lib.makeBinPath ( + [ + ripgrep + ] + # bun runs sysctl to detect if dunning on rosetta2 + ++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl + ) + } + + runHook postInstall + ''; + + postInstall = lib.optionalString (stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform) '' + # trick yargs into also generating zsh completions + installShellCompletion --cmd opencode \ + --bash <($out/bin/opencode completion) \ + --zsh <(SHELL=/bin/zsh $out/bin/opencode completion) + ''; + + nativeInstallCheckInputs = [ + versionCheckHook + writableTmpDirAsHomeHook + ]; + doInstallCheck = true; + versionCheckKeepEnvironment = [ "HOME" ]; + versionCheckProgramArg = "--version"; + + passthru = { + jsonschema = "${placeholder "out"}/share/opencode/schema.json"; + }; + + meta = { + description = "The open source coding agent"; + homepage = "https://opencode.ai/"; + license = lib.licenses.mit; + mainProgram = "opencode"; + inherit (node_modules.meta) platforms; + }; +}) diff --git a/nix/scripts/canonicalize-node-modules.ts b/nix/scripts/canonicalize-node-modules.ts new file mode 100644 index 00000000000..faa6f63402e --- /dev/null +++ b/nix/scripts/canonicalize-node-modules.ts @@ -0,0 +1,113 @@ +import { lstat, mkdir, readdir, rm, symlink } from "fs/promises" +import { join, relative } from "path" + +type SemverLike = { + valid: (value: string) => string | null + rcompare: (left: string, right: string) => number +} + +type Entry = { + dir: string + version: string + label: string +} + +const root = process.cwd() +const bunRoot = join(root, "node_modules/.bun") +const linkRoot = join(bunRoot, "node_modules") +const directories = (await readdir(bunRoot)).sort() +const versions = new Map() + +for (const entry of directories) { + const full = join(bunRoot, entry) + const info = await lstat(full) + if (!info.isDirectory()) { + continue + } + const parsed = parseEntry(entry) + if (!parsed) { + continue + } + const list = versions.get(parsed.name) ?? [] + list.push({ dir: full, version: parsed.version, label: entry }) + versions.set(parsed.name, list) +} + +const semverModule = (await import(join(bunRoot, "node_modules/semver"))) as + | SemverLike + | { + default: SemverLike + } +const semver = "default" in semverModule ? semverModule.default : semverModule +const selections = new Map() + +for (const [slug, list] of versions) { + list.sort((a, b) => { + const left = semver.valid(a.version) + const right = semver.valid(b.version) + if (left && right) { + const delta = semver.rcompare(left, right) + if (delta !== 0) { + return delta + } + } + if (left && !right) { + return -1 + } + if (!left && right) { + return 1 + } + return b.version.localeCompare(a.version) + }) + selections.set(slug, list[0]) +} + +await rm(linkRoot, { recursive: true, force: true }) +await mkdir(linkRoot, { recursive: true }) + +const rewrites: string[] = [] + +for (const [slug, entry] of Array.from(selections.entries()).sort((a, b) => a[0].localeCompare(b[0]))) { + const parts = slug.split("/") + const leaf = parts.pop() + if (!leaf) { + continue + } + const parent = join(linkRoot, ...parts) + await mkdir(parent, { recursive: true }) + const linkPath = join(parent, leaf) + const desired = join(entry.dir, "node_modules", slug) + const exists = await lstat(desired) + .then((info) => info.isDirectory()) + .catch(() => false) + if (!exists) { + continue + } + const relativeTarget = relative(parent, desired) + const resolved = relativeTarget.length === 0 ? "." : relativeTarget + await rm(linkPath, { recursive: true, force: true }) + await symlink(resolved, linkPath) + rewrites.push(slug + " -> " + resolved) +} + +rewrites.sort() +console.log("[canonicalize-node-modules] rebuilt", rewrites.length, "links") +for (const line of rewrites.slice(0, 20)) { + console.log(" ", line) +} +if (rewrites.length > 20) { + console.log(" ...") +} + +function parseEntry(label: string) { + const marker = label.startsWith("@") ? label.indexOf("@", 1) : label.indexOf("@") + if (marker <= 0) { + return null + } + const name = label.slice(0, marker).replace(/\+/g, "/") + const version = label.slice(marker + 1) + if (!name || !version) { + return null + } + return { name, version } +} diff --git a/nix/scripts/normalize-bun-binaries.ts b/nix/scripts/normalize-bun-binaries.ts new file mode 100644 index 00000000000..531d8fd0567 --- /dev/null +++ b/nix/scripts/normalize-bun-binaries.ts @@ -0,0 +1,138 @@ +import { lstat, mkdir, readdir, rm, symlink } from "fs/promises" +import { join, relative } from "path" + +type PackageManifest = { + name?: string + bin?: string | Record +} + +const root = process.cwd() +const bunRoot = join(root, "node_modules/.bun") +const bunEntries = (await safeReadDir(bunRoot)).sort() +let rewritten = 0 + +for (const entry of bunEntries) { + const modulesRoot = join(bunRoot, entry, "node_modules") + if (!(await exists(modulesRoot))) { + continue + } + const binRoot = join(modulesRoot, ".bin") + await rm(binRoot, { recursive: true, force: true }) + await mkdir(binRoot, { recursive: true }) + + const packageDirs = await collectPackages(modulesRoot) + for (const packageDir of packageDirs) { + const manifest = await readManifest(packageDir) + if (!manifest) { + continue + } + const binField = manifest.bin + if (!binField) { + continue + } + const seen = new Set() + if (typeof binField === "string") { + const fallback = manifest.name ?? packageDir.split("/").pop() + if (fallback) { + await linkBinary(binRoot, fallback, packageDir, binField, seen) + } + } else { + const entries = Object.entries(binField).sort((a, b) => a[0].localeCompare(b[0])) + for (const [name, target] of entries) { + await linkBinary(binRoot, name, packageDir, target, seen) + } + } + } +} + +console.log(`[normalize-bun-binaries] rewrote ${rewritten} links`) + +async function collectPackages(modulesRoot: string) { + const found: string[] = [] + const topLevel = (await safeReadDir(modulesRoot)).sort() + for (const name of topLevel) { + if (name === ".bin" || name === ".bun") { + continue + } + const full = join(modulesRoot, name) + if (!(await isDirectory(full))) { + continue + } + if (name.startsWith("@")) { + const scoped = (await safeReadDir(full)).sort() + for (const child of scoped) { + const scopedDir = join(full, child) + if (await isDirectory(scopedDir)) { + found.push(scopedDir) + } + } + continue + } + found.push(full) + } + return found.sort() +} + +async function readManifest(dir: string) { + const file = Bun.file(join(dir, "package.json")) + if (!(await file.exists())) { + return null + } + const data = (await file.json()) as PackageManifest + return data +} + +async function linkBinary(binRoot: string, name: string, packageDir: string, target: string, seen: Set) { + if (!name || !target) { + return + } + const normalizedName = normalizeBinName(name) + if (seen.has(normalizedName)) { + return + } + const resolved = join(packageDir, target) + const script = Bun.file(resolved) + if (!(await script.exists())) { + return + } + seen.add(normalizedName) + const destination = join(binRoot, normalizedName) + const relativeTarget = relative(binRoot, resolved) || "." + await rm(destination, { force: true }) + await symlink(relativeTarget, destination) + rewritten++ +} + +async function exists(path: string) { + try { + await lstat(path) + return true + } catch { + return false + } +} + +async function isDirectory(path: string) { + try { + const info = await lstat(path) + return info.isDirectory() + } catch { + return false + } +} + +async function safeReadDir(path: string) { + try { + return await readdir(path) + } catch { + return [] + } +} + +function normalizeBinName(name: string) { + const slash = name.lastIndexOf("/") + if (slash >= 0) { + return name.slice(slash + 1) + } + return name +} diff --git a/opencode.json b/opencode.json deleted file mode 100644 index 59f14ac7522..00000000000 --- a/opencode.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "context7": { - "type": "remote", - "url": "https://mcp.context7.com/sse" - }, - "weather": { - "type": "local", - "command": ["opencode", "x", "@h1deya/mcp-server-weather"] - } - } -} diff --git a/package.json b/package.json index 0bd1560cd7a..4267ef64566 100644 --- a/package.json +++ b/package.json @@ -1,42 +1,86 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "opencode", + "description": "AI-powered development tool", "private": true, "type": "module", - "packageManager": "bun@1.2.19", + "packageManager": "bun@1.3.5", "scripts": { - "dev": "bun run --conditions=development packages/opencode/src/index.ts", - "typecheck": "bun run --filter='*' typecheck", - "generate": "(cd packages/sdk && ./js/script/generate.ts) && (cd packages/sdk/stainless && ./generate.ts)", - "postinstall": "./script/hooks" + "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", + "typecheck": "bun turbo typecheck", + "prepare": "husky", + "random": "echo 'Random script'", + "hello": "echo 'Hello World!'", + "test": "echo 'do not run tests from root' && exit 1" }, "workspaces": { "packages": [ - "cloud/*", "packages/*", - "packages/sdk/js" + "packages/console/*", + "packages/sdk/js", + "packages/slack" ], "catalog": { + "@types/bun": "1.3.5", + "@octokit/rest": "22.0.0", "@hono/zod-validator": "0.4.2", + "ulid": "3.0.1", + "@kobalte/core": "0.13.11", + "@types/luxon": "3.7.1", "@types/node": "22.13.9", + "@types/semver": "7.7.1", "@tsconfig/node22": "22.0.2", - "ai": "5.0.8", - "hono": "4.7.10", + "@tsconfig/bun": "1.0.9", + "@cloudflare/workers-types": "4.20251008.0", + "@openauthjs/openauth": "0.0.0-20250322224806", + "@pierre/diffs": "1.0.2", + "@solid-primitives/storage": "4.3.3", + "@tailwindcss/vite": "4.1.11", + "diff": "8.0.2", + "dompurify": "3.3.1", + "ai": "5.0.119", + "hono": "4.10.7", + "hono-openapi": "1.1.2", + "fuzzysort": "3.1.0", + "luxon": "3.6.1", + "marked": "17.0.1", + "marked-shiki": "1.2.1", + "@playwright/test": "1.51.0", "typescript": "5.8.2", - "zod": "3.25.76", - "remeda": "2.26.0" + "@typescript/native-preview": "7.0.0-dev.20251207.1", + "zod": "4.1.8", + "remeda": "2.26.0", + "shiki": "3.20.0", + "solid-list": "0.3.0", + "tailwindcss": "4.1.11", + "virtua": "0.42.3", + "vite": "7.1.4", + "@solidjs/meta": "0.29.4", + "@solidjs/router": "0.15.4", + "@solidjs/start": "https://pkg.pr.new/@solidjs/start@dfb2020", + "solid-js": "1.9.10", + "vite-plugin-solid": "2.11.10" } }, - "dependencies": { - "pulumi-stripe": "0.0.24" - }, "devDependencies": { - "prettier": "3.5.3", - "sst": "3.17.8" + "@actions/artifact": "5.0.1", + "@tsconfig/bun": "catalog:", + "husky": "9.1.7", + "prettier": "3.6.2", + "semver": "^7.6.0", + "sst": "3.17.23", + "turbo": "2.5.6" + }, + "dependencies": { + "@aws-sdk/client-s3": "3.933.0", + "@opencode-ai/plugin": "workspace:*", + "@opencode-ai/script": "workspace:*", + "@opencode-ai/sdk": "workspace:*", + "typescript": "catalog:" }, "repository": { "type": "git", - "url": "https://github.com/sst/opencode" + "url": "https://github.com/anomalyco/opencode" }, "license": "MIT", "prettier": { @@ -46,10 +90,15 @@ "trustedDependencies": [ "esbuild", "protobufjs", - "sharp", "tree-sitter", "tree-sitter-bash", "web-tree-sitter" ], - "patchedDependencies": {} + "overrides": { + "@types/bun": "catalog:", + "@types/node": "catalog:" + }, + "patchedDependencies": { + "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch" + } } diff --git a/packages/app/.gitignore b/packages/app/.gitignore new file mode 100644 index 00000000000..d699efb38d2 --- /dev/null +++ b/packages/app/.gitignore @@ -0,0 +1,3 @@ +src/assets/theme.css +e2e/test-results +e2e/playwright-report diff --git a/packages/app/AGENTS.md b/packages/app/AGENTS.md new file mode 100644 index 00000000000..765e960c817 --- /dev/null +++ b/packages/app/AGENTS.md @@ -0,0 +1,30 @@ +## Debugging + +- NEVER try to restart the app, or the server process, EVER. + +## Local Dev + +- `opencode dev web` proxies `https://app.opencode.ai`, so local UI/CSS changes will not show there. +- For local UI changes, run the backend and app dev servers separately. +- Backend (from `packages/opencode`): `bun run --conditions=browser ./src/index.ts serve --port 4096` +- App (from `packages/app`): `bun dev -- --port 4444` +- Open `http://localhost:4444` to verify UI changes (it targets the backend at `http://localhost:4096`). + +## SolidJS + +- Always prefer `createStore` over multiple `createSignal` calls + +## Tool Calling + +- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. + +## Browser Automation + +Use `agent-browser` for web automation. Run `agent-browser --help` for all commands. + +Core workflow: + +1. `agent-browser open ` - Navigate to page +2. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2) +3. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs +4. Re-snapshot after page changes diff --git a/packages/app/README.md b/packages/app/README.md new file mode 100644 index 00000000000..54d1b2861b6 --- /dev/null +++ b/packages/app/README.md @@ -0,0 +1,51 @@ +## Usage + +Dependencies for these templates are managed with [pnpm](https://pnpm.io) using `pnpm up -Lri`. + +This is the reason you see a `pnpm-lock.yaml`. That said, any package manager will work. This file can safely be removed once you clone a template. + +```bash +$ npm install # or pnpm install or yarn install +``` + +### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs) + +## Available Scripts + +In the project directory, you can run: + +### `npm run dev` or `npm start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+ +### `npm run build` + +Builds the app for production to the `dist` folder.
+It correctly bundles Solid in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +## E2E Testing + +Playwright starts the Vite dev server automatically via `webServer`, and UI tests need an opencode backend (defaults to `localhost:4096`). +Use the local runner to create a temp sandbox, seed data, and run the tests. + +```bash +bunx playwright install +bun run test:e2e:local +bun run test:e2e:local -- --grep "settings" +``` + +Environment options: + +- `PLAYWRIGHT_SERVER_HOST` / `PLAYWRIGHT_SERVER_PORT` (backend address, default: `localhost:4096`) +- `PLAYWRIGHT_PORT` (Vite dev server port, default: `3000`) +- `PLAYWRIGHT_BASE_URL` (override base URL, default: `http://localhost:`) + +## Deployment + +You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.) diff --git a/packages/app/bunfig.toml b/packages/app/bunfig.toml new file mode 100644 index 00000000000..36399045119 --- /dev/null +++ b/packages/app/bunfig.toml @@ -0,0 +1,2 @@ +[test] +preload = ["./happydom.ts"] diff --git a/packages/app/e2e/context.spec.ts b/packages/app/e2e/context.spec.ts new file mode 100644 index 00000000000..beabd2eb7dd --- /dev/null +++ b/packages/app/e2e/context.spec.ts @@ -0,0 +1,45 @@ +import { test, expect } from "./fixtures" +import { promptSelector } from "./utils" + +test("context panel can be opened from the prompt", async ({ page, sdk, gotoSession }) => { + const title = `e2e smoke context ${Date.now()}` + const created = await sdk.session.create({ title }).then((r) => r.data) + + if (!created?.id) throw new Error("Session create did not return an id") + const sessionID = created.id + + try { + await sdk.session.promptAsync({ + sessionID, + noReply: true, + parts: [ + { + type: "text", + text: "seed context", + }, + ], + }) + + await expect + .poll(async () => { + const messages = await sdk.session.messages({ sessionID, limit: 1 }).then((r) => r.data ?? []) + return messages.length + }) + .toBeGreaterThan(0) + + await gotoSession(sessionID) + + const contextButton = page + .locator('[data-component="button"]') + .filter({ has: page.locator('[data-component="progress-circle"]').first() }) + .first() + + await expect(contextButton).toBeVisible() + await contextButton.click() + + const tabs = page.locator('[data-component="tabs"][data-variant="normal"]') + await expect(tabs.getByRole("tab", { name: "Context" })).toBeVisible() + } finally { + await sdk.session.delete({ sessionID }).catch(() => undefined) + } +}) diff --git a/packages/app/e2e/file-open.spec.ts b/packages/app/e2e/file-open.spec.ts new file mode 100644 index 00000000000..fb7104b6b05 --- /dev/null +++ b/packages/app/e2e/file-open.spec.ts @@ -0,0 +1,23 @@ +import { test, expect } from "./fixtures" +import { modKey } from "./utils" + +test("can open a file tab from the search palette", async ({ page, gotoSession }) => { + await gotoSession() + + await page.keyboard.press(`${modKey}+P`) + + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + + const input = dialog.getByRole("textbox").first() + await input.fill("package.json") + + const fileItem = dialog.locator('[data-slot="list-item"][data-key^="file:"]').first() + await expect(fileItem).toBeVisible() + await fileItem.click() + + await expect(dialog).toHaveCount(0) + + const tabs = page.locator('[data-component="tabs"][data-variant="normal"]') + await expect(tabs.locator('[data-slot="tabs-trigger"]').first()).toBeVisible() +}) diff --git a/packages/app/e2e/file-viewer.spec.ts b/packages/app/e2e/file-viewer.spec.ts new file mode 100644 index 00000000000..1e0f8a6f23a --- /dev/null +++ b/packages/app/e2e/file-viewer.spec.ts @@ -0,0 +1,35 @@ +import { test, expect } from "./fixtures" +import { modKey } from "./utils" + +test("smoke file viewer renders real file content", async ({ page, gotoSession }) => { + await gotoSession() + + const sep = process.platform === "win32" ? "\\" : "/" + const file = ["packages", "app", "package.json"].join(sep) + + await page.keyboard.press(`${modKey}+P`) + + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + + const input = dialog.getByRole("textbox").first() + await input.fill(file) + + const fileItem = dialog + .locator( + '[data-slot="list-item"][data-key^="file:"][data-key*="packages"][data-key*="app"][data-key$="package.json"]', + ) + .first() + await expect(fileItem).toBeVisible() + await fileItem.click() + + await expect(dialog).toHaveCount(0) + + const tab = page.getByRole("tab", { name: "package.json" }) + await expect(tab).toBeVisible() + await tab.click() + + const code = page.locator('[data-component="code"]').first() + await expect(code).toBeVisible() + await expect(code.getByText("@opencode-ai/app")).toBeVisible() +}) diff --git a/packages/app/e2e/fixtures.ts b/packages/app/e2e/fixtures.ts new file mode 100644 index 00000000000..721d60049ce --- /dev/null +++ b/packages/app/e2e/fixtures.ts @@ -0,0 +1,40 @@ +import { test as base, expect } from "@playwright/test" +import { createSdk, dirSlug, getWorktree, promptSelector, sessionPath } from "./utils" + +type TestFixtures = { + sdk: ReturnType + gotoSession: (sessionID?: string) => Promise +} + +type WorkerFixtures = { + directory: string + slug: string +} + +export const test = base.extend({ + directory: [ + async ({}, use) => { + const directory = await getWorktree() + await use(directory) + }, + { scope: "worker" }, + ], + slug: [ + async ({ directory }, use) => { + await use(dirSlug(directory)) + }, + { scope: "worker" }, + ], + sdk: async ({ directory }, use) => { + await use(createSdk(directory)) + }, + gotoSession: async ({ page, directory }, use) => { + const gotoSession = async (sessionID?: string) => { + await page.goto(sessionPath(directory, sessionID)) + await expect(page.locator(promptSelector)).toBeVisible() + } + await use(gotoSession) + }, +}) + +export { expect } diff --git a/packages/app/e2e/home.spec.ts b/packages/app/e2e/home.spec.ts new file mode 100644 index 00000000000..c6fb0e3b074 --- /dev/null +++ b/packages/app/e2e/home.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from "./fixtures" +import { serverName } from "./utils" + +test("home renders and shows core entrypoints", async ({ page }) => { + await page.goto("/") + + await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible() + await expect(page.getByRole("button", { name: serverName })).toBeVisible() +}) + +test("server picker dialog opens from home", async ({ page }) => { + await page.goto("/") + + const trigger = page.getByRole("button", { name: serverName }) + await expect(trigger).toBeVisible() + await trigger.click() + + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + await expect(dialog.getByRole("textbox").first()).toBeVisible() +}) diff --git a/packages/app/e2e/model-picker.spec.ts b/packages/app/e2e/model-picker.spec.ts new file mode 100644 index 00000000000..9e64b3dfb0a --- /dev/null +++ b/packages/app/e2e/model-picker.spec.ts @@ -0,0 +1,43 @@ +import { test, expect } from "./fixtures" +import { promptSelector } from "./utils" + +test("smoke model selection updates prompt footer", async ({ page, gotoSession }) => { + await gotoSession() + + await page.locator(promptSelector).click() + await page.keyboard.type("/model") + + const command = page.locator('[data-slash-id="model.choose"]') + await expect(command).toBeVisible() + await command.hover() + + await page.keyboard.press("Enter") + + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + + const input = dialog.getByRole("textbox").first() + + const selected = dialog.locator('[data-slot="list-item"][data-selected="true"]').first() + await expect(selected).toBeVisible() + + const other = dialog.locator('[data-slot="list-item"]:not([data-selected="true"])').first() + const target = (await other.count()) > 0 ? other : selected + + const key = await target.getAttribute("data-key") + if (!key) throw new Error("Failed to resolve model key from list item") + + const name = (await target.locator("span").first().innerText()).trim() + const model = key.split(":").slice(1).join(":") + + await input.fill(model) + + const item = dialog.locator(`[data-slot="list-item"][data-key="${key}"]`) + await expect(item).toBeVisible() + await item.click() + + await expect(dialog).toHaveCount(0) + + const form = page.locator(promptSelector).locator("xpath=ancestor::form[1]") + await expect(form.locator('[data-component="button"]').filter({ hasText: name }).first()).toBeVisible() +}) diff --git a/packages/app/e2e/navigation.spec.ts b/packages/app/e2e/navigation.spec.ts new file mode 100644 index 00000000000..76923af6ede --- /dev/null +++ b/packages/app/e2e/navigation.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from "./fixtures" +import { dirPath, promptSelector } from "./utils" + +test("project route redirects to /session", async ({ page, directory, slug }) => { + await page.goto(dirPath(directory)) + + await expect(page).toHaveURL(new RegExp(`/${slug}/session`)) + await expect(page.locator(promptSelector)).toBeVisible() +}) diff --git a/packages/app/e2e/palette.spec.ts b/packages/app/e2e/palette.spec.ts new file mode 100644 index 00000000000..617c55ac167 --- /dev/null +++ b/packages/app/e2e/palette.spec.ts @@ -0,0 +1,15 @@ +import { test, expect } from "./fixtures" +import { modKey } from "./utils" + +test("search palette opens and closes", async ({ page, gotoSession }) => { + await gotoSession() + + await page.keyboard.press(`${modKey}+P`) + + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + await expect(dialog.getByRole("textbox").first()).toBeVisible() + + await page.keyboard.press("Escape") + await expect(dialog).toHaveCount(0) +}) diff --git a/packages/app/e2e/prompt-mention.spec.ts b/packages/app/e2e/prompt-mention.spec.ts new file mode 100644 index 00000000000..113b8465f71 --- /dev/null +++ b/packages/app/e2e/prompt-mention.spec.ts @@ -0,0 +1,26 @@ +import { test, expect } from "./fixtures" +import { promptSelector } from "./utils" + +test("smoke @mention inserts file pill token", async ({ page, gotoSession }) => { + await gotoSession() + + await page.locator(promptSelector).click() + const sep = process.platform === "win32" ? "\\" : "/" + const file = ["packages", "app", "package.json"].join(sep) + const filePattern = /packages[\\/]+app[\\/]+\s*package\.json/ + + await page.keyboard.type(`@${file}`) + + const suggestion = page.getByRole("button", { name: filePattern }).first() + await expect(suggestion).toBeVisible() + await suggestion.hover() + + await page.keyboard.press("Tab") + + const pill = page.locator(`${promptSelector} [data-type="file"]`).first() + await expect(pill).toBeVisible() + await expect(pill).toHaveAttribute("data-path", filePattern) + + await page.keyboard.type(" ok") + await expect(page.locator(promptSelector)).toContainText("ok") +}) diff --git a/packages/app/e2e/prompt-slash-open.spec.ts b/packages/app/e2e/prompt-slash-open.spec.ts new file mode 100644 index 00000000000..3c29d405c18 --- /dev/null +++ b/packages/app/e2e/prompt-slash-open.spec.ts @@ -0,0 +1,22 @@ +import { test, expect } from "./fixtures" +import { promptSelector } from "./utils" + +test("smoke /open opens file picker dialog", async ({ page, gotoSession }) => { + await gotoSession() + + await page.locator(promptSelector).click() + await page.keyboard.type("/open") + + const command = page.locator('[data-slash-id="file.open"]') + await expect(command).toBeVisible() + await command.hover() + + await page.keyboard.press("Enter") + + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + await expect(dialog.getByRole("textbox").first()).toBeVisible() + + await page.keyboard.press("Escape") + await expect(dialog).toHaveCount(0) +}) diff --git a/packages/app/e2e/prompt.spec.ts b/packages/app/e2e/prompt.spec.ts new file mode 100644 index 00000000000..3e5892ce8d5 --- /dev/null +++ b/packages/app/e2e/prompt.spec.ts @@ -0,0 +1,62 @@ +import { test, expect } from "./fixtures" +import { promptSelector } from "./utils" + +function sessionIDFromUrl(url: string) { + const match = /\/session\/([^/?#]+)/.exec(url) + return match?.[1] +} + +test("can send a prompt and receive a reply", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + const pageErrors: string[] = [] + const onPageError = (err: Error) => { + pageErrors.push(err.message) + } + page.on("pageerror", onPageError) + + await gotoSession() + + const token = `E2E_OK_${Date.now()}` + + const prompt = page.locator(promptSelector) + await prompt.click() + await page.keyboard.type(`Reply with exactly: ${token}`) + await page.keyboard.press("Enter") + + await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 }) + + const sessionID = (() => { + const id = sessionIDFromUrl(page.url()) + if (!id) throw new Error(`Failed to parse session id from url: ${page.url()}`) + return id + })() + + try { + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? []) + return messages + .filter((m) => m.info.role === "assistant") + .flatMap((m) => m.parts) + .filter((p) => p.type === "text") + .map((p) => p.text) + .join("\n") + }, + { timeout: 90_000 }, + ) + + .toContain(token) + + const reply = page.locator('[data-slot="session-turn-summary-section"]').filter({ hasText: token }).first() + await expect(reply).toBeVisible({ timeout: 90_000 }) + } finally { + page.off("pageerror", onPageError) + await sdk.session.delete({ sessionID }).catch(() => undefined) + } + + if (pageErrors.length > 0) { + throw new Error(`Page error(s):\n${pageErrors.join("\n")}`) + } +}) diff --git a/packages/app/e2e/session.spec.ts b/packages/app/e2e/session.spec.ts new file mode 100644 index 00000000000..19e25a42131 --- /dev/null +++ b/packages/app/e2e/session.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from "./fixtures" +import { promptSelector } from "./utils" + +test("can open an existing session and type into the prompt", async ({ page, sdk, gotoSession }) => { + const title = `e2e smoke ${Date.now()}` + const created = await sdk.session.create({ title }).then((r) => r.data) + + if (!created?.id) throw new Error("Session create did not return an id") + const sessionID = created.id + + try { + await gotoSession(sessionID) + + const prompt = page.locator(promptSelector) + await prompt.click() + await page.keyboard.type("hello from e2e") + await expect(prompt).toContainText("hello from e2e") + } finally { + await sdk.session.delete({ sessionID }).catch(() => undefined) + } +}) diff --git a/packages/app/e2e/settings.spec.ts b/packages/app/e2e/settings.spec.ts new file mode 100644 index 00000000000..09dc942cc92 --- /dev/null +++ b/packages/app/e2e/settings.spec.ts @@ -0,0 +1,44 @@ +import { test, expect } from "./fixtures" +import { modKey } from "./utils" + +test("smoke settings dialog opens, switches tabs, closes", async ({ page, gotoSession }) => { + await gotoSession() + + const dialog = page.getByRole("dialog") + + await page.keyboard.press(`${modKey}+Comma`).catch(() => undefined) + + const opened = await dialog + .waitFor({ state: "visible", timeout: 3000 }) + .then(() => true) + .catch(() => false) + + if (!opened) { + await page.getByRole("button", { name: "Settings" }).first().click() + await expect(dialog).toBeVisible() + } + + await dialog.getByRole("tab", { name: "Shortcuts" }).click() + await expect(dialog.getByRole("button", { name: "Reset to defaults" })).toBeVisible() + await expect(dialog.getByPlaceholder("Search shortcuts")).toBeVisible() + + await page.keyboard.press("Escape") + + const closed = await dialog + .waitFor({ state: "detached", timeout: 1500 }) + .then(() => true) + .catch(() => false) + + if (closed) return + + await page.keyboard.press("Escape") + const closedSecond = await dialog + .waitFor({ state: "detached", timeout: 1500 }) + .then(() => true) + .catch(() => false) + + if (closedSecond) return + + await page.locator('[data-component="dialog-overlay"]').click({ position: { x: 5, y: 5 } }) + await expect(dialog).toHaveCount(0) +}) diff --git a/packages/app/e2e/sidebar.spec.ts b/packages/app/e2e/sidebar.spec.ts new file mode 100644 index 00000000000..925590f5106 --- /dev/null +++ b/packages/app/e2e/sidebar.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from "./fixtures" +import { modKey } from "./utils" + +test("sidebar can be collapsed and expanded", async ({ page, gotoSession }) => { + await gotoSession() + + const main = page.locator("main") + const closedClass = /xl:border-l/ + const isClosed = await main.evaluate((node) => node.className.includes("xl:border-l")) + + if (isClosed) { + await page.keyboard.press(`${modKey}+B`) + await expect(main).not.toHaveClass(closedClass) + } + + await page.keyboard.press(`${modKey}+B`) + await expect(main).toHaveClass(closedClass) + + await page.keyboard.press(`${modKey}+B`) + await expect(main).not.toHaveClass(closedClass) +}) diff --git a/packages/app/e2e/terminal-init.spec.ts b/packages/app/e2e/terminal-init.spec.ts new file mode 100644 index 00000000000..cfde2d01930 --- /dev/null +++ b/packages/app/e2e/terminal-init.spec.ts @@ -0,0 +1,25 @@ +import { test, expect } from "./fixtures" +import { promptSelector, terminalSelector, terminalToggleKey } from "./utils" + +test("smoke terminal mounts and can create a second tab", async ({ page, gotoSession }) => { + await gotoSession() + + const terminals = page.locator(terminalSelector) + const opened = await terminals.first().isVisible() + + if (!opened) { + await page.keyboard.press(terminalToggleKey) + } + + await expect(terminals.first()).toBeVisible() + await expect(terminals.first().locator("textarea")).toHaveCount(1) + await expect(terminals).toHaveCount(1) + + // Ghostty captures a lot of keybinds when focused; move focus back + // to the app shell before triggering `terminal.new`. + await page.locator(promptSelector).click() + await page.keyboard.press("Control+Alt+T") + + await expect(terminals).toHaveCount(2) + await expect(terminals.nth(1).locator("textarea")).toHaveCount(1) +}) diff --git a/packages/app/e2e/terminal.spec.ts b/packages/app/e2e/terminal.spec.ts new file mode 100644 index 00000000000..fc558b63259 --- /dev/null +++ b/packages/app/e2e/terminal.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "./fixtures" +import { terminalSelector, terminalToggleKey } from "./utils" + +test("terminal panel can be toggled", async ({ page, gotoSession }) => { + await gotoSession() + + const terminal = page.locator(terminalSelector) + const initiallyOpen = await terminal.isVisible() + if (initiallyOpen) { + await page.keyboard.press(terminalToggleKey) + await expect(terminal).toHaveCount(0) + } + + await page.keyboard.press(terminalToggleKey) + await expect(terminal).toBeVisible() +}) diff --git a/packages/app/e2e/tsconfig.json b/packages/app/e2e/tsconfig.json new file mode 100644 index 00000000000..76438a03cc8 --- /dev/null +++ b/packages/app/e2e/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "noEmit": true, + "types": ["node"] + }, + "include": ["./**/*.ts"] +} diff --git a/packages/app/e2e/utils.ts b/packages/app/e2e/utils.ts new file mode 100644 index 00000000000..eb0395950ae --- /dev/null +++ b/packages/app/e2e/utils.ts @@ -0,0 +1,38 @@ +import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" +import { base64Encode } from "@opencode-ai/util/encode" + +export const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" +export const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" + +export const serverUrl = `http://${serverHost}:${serverPort}` +export const serverName = `${serverHost}:${serverPort}` + +export const modKey = process.platform === "darwin" ? "Meta" : "Control" +export const terminalToggleKey = "Control+Backquote" + +export const promptSelector = '[data-component="prompt-input"]' +export const terminalSelector = '[data-component="terminal"]' + +export function createSdk(directory?: string) { + return createOpencodeClient({ baseUrl: serverUrl, directory, throwOnError: true }) +} + +export async function getWorktree() { + const sdk = createSdk() + const result = await sdk.path.get() + const data = result.data + if (!data?.worktree) throw new Error(`Failed to resolve a worktree from ${serverUrl}/path`) + return data.worktree +} + +export function dirSlug(directory: string) { + return base64Encode(directory) +} + +export function dirPath(directory: string) { + return `/${dirSlug(directory)}` +} + +export function sessionPath(directory: string, sessionID?: string) { + return `${dirPath(directory)}/session${sessionID ? `/${sessionID}` : ""}` +} diff --git a/packages/app/happydom.ts b/packages/app/happydom.ts new file mode 100644 index 00000000000..de726718f6f --- /dev/null +++ b/packages/app/happydom.ts @@ -0,0 +1,75 @@ +import { GlobalRegistrator } from "@happy-dom/global-registrator" + +GlobalRegistrator.register() + +const originalGetContext = HTMLCanvasElement.prototype.getContext +// @ts-expect-error - we're overriding with a simplified mock +HTMLCanvasElement.prototype.getContext = function (contextType: string, _options?: unknown) { + if (contextType === "2d") { + return { + canvas: this, + fillStyle: "#000000", + strokeStyle: "#000000", + font: "12px monospace", + textAlign: "start", + textBaseline: "alphabetic", + globalAlpha: 1, + globalCompositeOperation: "source-over", + imageSmoothingEnabled: true, + lineWidth: 1, + lineCap: "butt", + lineJoin: "miter", + miterLimit: 10, + shadowBlur: 0, + shadowColor: "rgba(0, 0, 0, 0)", + shadowOffsetX: 0, + shadowOffsetY: 0, + fillRect: () => {}, + strokeRect: () => {}, + clearRect: () => {}, + fillText: () => {}, + strokeText: () => {}, + measureText: (text: string) => ({ width: text.length * 8 }), + drawImage: () => {}, + save: () => {}, + restore: () => {}, + scale: () => {}, + rotate: () => {}, + translate: () => {}, + transform: () => {}, + setTransform: () => {}, + resetTransform: () => {}, + createLinearGradient: () => ({ addColorStop: () => {} }), + createRadialGradient: () => ({ addColorStop: () => {} }), + createPattern: () => null, + beginPath: () => {}, + closePath: () => {}, + moveTo: () => {}, + lineTo: () => {}, + bezierCurveTo: () => {}, + quadraticCurveTo: () => {}, + arc: () => {}, + arcTo: () => {}, + ellipse: () => {}, + rect: () => {}, + fill: () => {}, + stroke: () => {}, + clip: () => {}, + isPointInPath: () => false, + isPointInStroke: () => false, + getTransform: () => ({}), + getImageData: () => ({ + data: new Uint8ClampedArray(0), + width: 0, + height: 0, + }), + putImageData: () => {}, + createImageData: () => ({ + data: new Uint8ClampedArray(0), + width: 0, + height: 0, + }), + } as unknown as CanvasRenderingContext2D + } + return originalGetContext.call(this, contextType as "2d", _options) +} diff --git a/packages/app/index.html b/packages/app/index.html new file mode 100644 index 00000000000..6fa34553510 --- /dev/null +++ b/packages/app/index.html @@ -0,0 +1,23 @@ + + + + + + OpenCode + + + + + + + + + + + + + +
+ + + diff --git a/packages/app/package.json b/packages/app/package.json new file mode 100644 index 00000000000..4212f679cf3 --- /dev/null +++ b/packages/app/package.json @@ -0,0 +1,69 @@ +{ + "name": "@opencode-ai/app", + "version": "1.1.32", + "description": "", + "type": "module", + "exports": { + ".": "./src/index.ts", + "./vite": "./vite.js" + }, + "scripts": { + "typecheck": "tsgo -b", + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "test": "playwright test", + "test:e2e": "playwright test", + "test:e2e:local": "bun script/e2e-local.ts", + "test:e2e:ui": "playwright test --ui", + "test:e2e:report": "playwright show-report e2e/playwright-report" + }, + "license": "MIT", + "devDependencies": { + "@happy-dom/global-registrator": "20.0.11", + "@playwright/test": "1.57.0", + "@tailwindcss/vite": "catalog:", + "@tsconfig/bun": "1.0.9", + "@types/bun": "catalog:", + "@types/luxon": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + "vite-plugin-icons-spritesheet": "3.0.1", + "vite-plugin-solid": "catalog:" + }, + "dependencies": { + "@kobalte/core": "catalog:", + "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@opencode-ai/util": "workspace:*", + "@shikijs/transformers": "3.9.2", + "@solid-primitives/active-element": "2.1.3", + "@solid-primitives/audio": "1.4.2", + "@solid-primitives/i18n": "2.2.1", + "@solid-primitives/event-bus": "1.1.2", + "@solid-primitives/media": "2.3.3", + "@solid-primitives/resize-observer": "2.1.3", + "@solid-primitives/scroll": "2.1.3", + "@solid-primitives/storage": "catalog:", + "@solid-primitives/websocket": "1.3.1", + "@solidjs/meta": "catalog:", + "@solidjs/router": "catalog:", + "@thisbeyond/solid-dnd": "0.7.5", + "diff": "catalog:", + "fuzzysort": "catalog:", + "ghostty-web": "0.3.0", + "luxon": "catalog:", + "marked": "catalog:", + "marked-shiki": "catalog:", + "remeda": "catalog:", + "shiki": "catalog:", + "solid-js": "catalog:", + "solid-list": "catalog:", + "tailwindcss": "catalog:", + "virtua": "catalog:", + "zod": "catalog:" + } +} diff --git a/packages/app/playwright.config.ts b/packages/app/playwright.config.ts new file mode 100644 index 00000000000..10819e69ffe --- /dev/null +++ b/packages/app/playwright.config.ts @@ -0,0 +1,43 @@ +import { defineConfig, devices } from "@playwright/test" + +const port = Number(process.env.PLAYWRIGHT_PORT ?? 3000) +const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? `http://localhost:${port}` +const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" +const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" +const command = `bun run dev -- --host 0.0.0.0 --port ${port}` +const reuse = !process.env.CI + +export default defineConfig({ + testDir: "./e2e", + outputDir: "./e2e/test-results", + timeout: 60_000, + expect: { + timeout: 10_000, + }, + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + reporter: [["html", { outputFolder: "e2e/playwright-report", open: "never" }], ["line"]], + webServer: { + command, + url: baseURL, + reuseExistingServer: reuse, + timeout: 120_000, + env: { + VITE_OPENCODE_SERVER_HOST: serverHost, + VITE_OPENCODE_SERVER_PORT: serverPort, + }, + }, + use: { + baseURL, + trace: "on-first-retry", + screenshot: "only-on-failure", + video: "retain-on-failure", + }, + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + ], +}) diff --git a/packages/app/public/_headers b/packages/app/public/_headers new file mode 100644 index 00000000000..f5157b1debc --- /dev/null +++ b/packages/app/public/_headers @@ -0,0 +1,17 @@ +/assets/*.js + Content-Type: application/javascript + +/assets/*.mjs + Content-Type: application/javascript + +/assets/*.css + Content-Type: text/css + +/*.js + Content-Type: application/javascript + +/*.mjs + Content-Type: application/javascript + +/*.css + Content-Type: text/css diff --git a/packages/app/public/apple-touch-icon-v3.png b/packages/app/public/apple-touch-icon-v3.png new file mode 120000 index 00000000000..a6f48a689db --- /dev/null +++ b/packages/app/public/apple-touch-icon-v3.png @@ -0,0 +1 @@ +../../ui/src/assets/favicon/apple-touch-icon-v3.png \ No newline at end of file diff --git a/packages/app/public/apple-touch-icon.png b/packages/app/public/apple-touch-icon.png new file mode 120000 index 00000000000..fb6e8b1702d --- /dev/null +++ b/packages/app/public/apple-touch-icon.png @@ -0,0 +1 @@ +../../ui/src/assets/favicon/apple-touch-icon.png \ No newline at end of file diff --git a/packages/app/public/favicon-96x96-v3.png b/packages/app/public/favicon-96x96-v3.png new file mode 120000 index 00000000000..5d21163ce86 --- /dev/null +++ b/packages/app/public/favicon-96x96-v3.png @@ -0,0 +1 @@ +../../ui/src/assets/favicon/favicon-96x96-v3.png \ No newline at end of file diff --git a/packages/app/public/favicon-96x96.png b/packages/app/public/favicon-96x96.png new file mode 120000 index 00000000000..155c5ed2fc1 --- /dev/null +++ b/packages/app/public/favicon-96x96.png @@ -0,0 +1 @@ +../../ui/src/assets/favicon/favicon-96x96.png \ No newline at end of file diff --git a/packages/app/public/favicon-v3.ico b/packages/app/public/favicon-v3.ico new file mode 120000 index 00000000000..b3da91f3c45 --- /dev/null +++ b/packages/app/public/favicon-v3.ico @@ -0,0 +1 @@ +../../ui/src/assets/favicon/favicon-v3.ico \ No newline at end of file diff --git a/packages/app/public/favicon-v3.svg b/packages/app/public/favicon-v3.svg new file mode 120000 index 00000000000..fc95f68af4a --- /dev/null +++ b/packages/app/public/favicon-v3.svg @@ -0,0 +1 @@ +../../ui/src/assets/favicon/favicon-v3.svg \ No newline at end of file diff --git a/packages/app/public/favicon.ico b/packages/app/public/favicon.ico new file mode 120000 index 00000000000..1c90f01b16f --- /dev/null +++ b/packages/app/public/favicon.ico @@ -0,0 +1 @@ +../../ui/src/assets/favicon/favicon.ico \ No newline at end of file diff --git a/packages/app/public/favicon.svg b/packages/app/public/favicon.svg new file mode 120000 index 00000000000..80804d2579b --- /dev/null +++ b/packages/app/public/favicon.svg @@ -0,0 +1 @@ +../../ui/src/assets/favicon/favicon.svg \ No newline at end of file diff --git a/packages/app/public/oc-theme-preload.js b/packages/app/public/oc-theme-preload.js new file mode 100644 index 00000000000..f8c71049619 --- /dev/null +++ b/packages/app/public/oc-theme-preload.js @@ -0,0 +1,28 @@ +;(function () { + var themeId = localStorage.getItem("opencode-theme-id") + if (!themeId) return + + var scheme = localStorage.getItem("opencode-color-scheme") || "system" + var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches) + var mode = isDark ? "dark" : "light" + + document.documentElement.dataset.theme = themeId + document.documentElement.dataset.colorScheme = mode + + if (themeId === "oc-1") return + + var css = localStorage.getItem("opencode-theme-css-" + themeId + "-" + mode) + if (css) { + var style = document.createElement("style") + style.id = "oc-theme-preload" + style.textContent = + ":root{color-scheme:" + + mode + + ";--text-mix-blend-mode:" + + (isDark ? "plus-lighter" : "multiply") + + ";" + + css + + "}" + document.head.appendChild(style) + } +})() diff --git a/packages/app/public/site.webmanifest b/packages/app/public/site.webmanifest new file mode 120000 index 00000000000..a116d787962 --- /dev/null +++ b/packages/app/public/site.webmanifest @@ -0,0 +1 @@ +../../ui/src/assets/favicon/site.webmanifest \ No newline at end of file diff --git a/packages/app/public/social-share-zen.png b/packages/app/public/social-share-zen.png new file mode 120000 index 00000000000..02f205fc523 --- /dev/null +++ b/packages/app/public/social-share-zen.png @@ -0,0 +1 @@ +../../ui/src/assets/images/social-share-zen.png \ No newline at end of file diff --git a/packages/app/public/social-share.png b/packages/app/public/social-share.png new file mode 120000 index 00000000000..88bf2d4c654 --- /dev/null +++ b/packages/app/public/social-share.png @@ -0,0 +1 @@ +../../ui/src/assets/images/social-share.png \ No newline at end of file diff --git a/packages/app/public/web-app-manifest-192x192.png b/packages/app/public/web-app-manifest-192x192.png new file mode 120000 index 00000000000..8cfdf8ca55f --- /dev/null +++ b/packages/app/public/web-app-manifest-192x192.png @@ -0,0 +1 @@ +../../ui/src/assets/favicon/web-app-manifest-192x192.png \ No newline at end of file diff --git a/packages/app/public/web-app-manifest-512x512.png b/packages/app/public/web-app-manifest-512x512.png new file mode 120000 index 00000000000..4165998e654 --- /dev/null +++ b/packages/app/public/web-app-manifest-512x512.png @@ -0,0 +1 @@ +../../ui/src/assets/favicon/web-app-manifest-512x512.png \ No newline at end of file diff --git a/packages/app/script/e2e-local.ts b/packages/app/script/e2e-local.ts new file mode 100644 index 00000000000..aac2c15bb76 --- /dev/null +++ b/packages/app/script/e2e-local.ts @@ -0,0 +1,143 @@ +import fs from "node:fs/promises" +import net from "node:net" +import os from "node:os" +import path from "node:path" + +async function freePort() { + return await new Promise((resolve, reject) => { + const server = net.createServer() + server.once("error", reject) + server.listen(0, () => { + const address = server.address() + if (!address || typeof address === "string") { + server.close(() => reject(new Error("Failed to acquire a free port"))) + return + } + server.close((err) => { + if (err) { + reject(err) + return + } + resolve(address.port) + }) + }) + }) +} + +async function waitForHealth(url: string) { + const timeout = Date.now() + 120_000 + const errors: string[] = [] + while (Date.now() < timeout) { + const result = await fetch(url) + .then((r) => ({ ok: r.ok, error: undefined })) + .catch((error) => ({ + ok: false, + error: error instanceof Error ? error.message : String(error), + })) + if (result.ok) return + if (result.error) errors.push(result.error) + await new Promise((r) => setTimeout(r, 250)) + } + const last = errors.length ? ` (last error: ${errors[errors.length - 1]})` : "" + throw new Error(`Timed out waiting for server health: ${url}${last}`) +} + +const appDir = process.cwd() +const repoDir = path.resolve(appDir, "../..") +const opencodeDir = path.join(repoDir, "packages", "opencode") +const modelsJson = path.join(opencodeDir, "test", "tool", "fixtures", "models-api.json") + +const extraArgs = (() => { + const args = process.argv.slice(2) + if (args[0] === "--") return args.slice(1) + return args +})() + +const [serverPort, webPort] = await Promise.all([freePort(), freePort()]) + +const sandbox = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-e2e-")) + +const serverEnv = { + ...process.env, + MODELS_DEV_API_JSON: modelsJson, + OPENCODE_DISABLE_MODELS_FETCH: "true", + OPENCODE_DISABLE_SHARE: "true", + OPENCODE_DISABLE_LSP_DOWNLOAD: "true", + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true", + OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true", + OPENCODE_TEST_HOME: path.join(sandbox, "home"), + XDG_DATA_HOME: path.join(sandbox, "share"), + XDG_CACHE_HOME: path.join(sandbox, "cache"), + XDG_CONFIG_HOME: path.join(sandbox, "config"), + XDG_STATE_HOME: path.join(sandbox, "state"), + OPENCODE_E2E_PROJECT_DIR: repoDir, + OPENCODE_E2E_SESSION_TITLE: "E2E Session", + OPENCODE_E2E_MESSAGE: "Seeded for UI e2e", + OPENCODE_E2E_MODEL: "opencode/gpt-5-nano", + OPENCODE_CLIENT: "app", +} satisfies Record + +const runnerEnv = { + ...serverEnv, + PLAYWRIGHT_SERVER_HOST: "127.0.0.1", + PLAYWRIGHT_SERVER_PORT: String(serverPort), + VITE_OPENCODE_SERVER_HOST: "127.0.0.1", + VITE_OPENCODE_SERVER_PORT: String(serverPort), + PLAYWRIGHT_PORT: String(webPort), +} satisfies Record + +const seed = Bun.spawn(["bun", "script/seed-e2e.ts"], { + cwd: opencodeDir, + env: serverEnv, + stdout: "inherit", + stderr: "inherit", +}) + +const seedExit = await seed.exited +if (seedExit !== 0) { + process.exit(seedExit) +} + +Object.assign(process.env, serverEnv) +process.env.AGENT = "1" +process.env.OPENCODE = "1" + +const log = await import("../../opencode/src/util/log") +const install = await import("../../opencode/src/installation") +await log.Log.init({ + print: true, + dev: install.Installation.isLocal(), + level: "WARN", +}) + +const servermod = await import("../../opencode/src/server/server") +const inst = await import("../../opencode/src/project/instance") +const server = servermod.Server.listen({ port: serverPort, hostname: "127.0.0.1" }) +console.log(`opencode server listening on http://127.0.0.1:${serverPort}`) + +const result = await (async () => { + try { + await waitForHealth(`http://127.0.0.1:${serverPort}/global/health`) + + const runner = Bun.spawn(["bun", "test:e2e", ...extraArgs], { + cwd: appDir, + env: runnerEnv, + stdout: "inherit", + stderr: "inherit", + }) + + return { code: await runner.exited } + } catch (error) { + return { error } + } finally { + await inst.Instance.disposeAll() + await server.stop() + } +})() + +if ("error" in result) { + console.error(result.error) + process.exit(1) +} + +process.exit(result.code) diff --git a/packages/app/src/addons/serialize.test.ts b/packages/app/src/addons/serialize.test.ts new file mode 100644 index 00000000000..7f6780557da --- /dev/null +++ b/packages/app/src/addons/serialize.test.ts @@ -0,0 +1,319 @@ +import { describe, test, expect, beforeAll, afterEach } from "bun:test" +import { Terminal, Ghostty } from "ghostty-web" +import { SerializeAddon } from "./serialize" + +let ghostty: Ghostty +beforeAll(async () => { + ghostty = await Ghostty.load() +}) + +const terminals: Terminal[] = [] + +afterEach(() => { + for (const term of terminals) { + term.dispose() + } + terminals.length = 0 + document.body.innerHTML = "" +}) + +function createTerminal(cols = 80, rows = 24): { term: Terminal; addon: SerializeAddon; container: HTMLElement } { + const container = document.createElement("div") + document.body.appendChild(container) + + const term = new Terminal({ cols, rows, ghostty }) + const addon = new SerializeAddon() + term.loadAddon(addon) + term.open(container) + terminals.push(term) + + return { term, addon, container } +} + +function writeAndWait(term: Terminal, data: string): Promise { + return new Promise((resolve) => { + term.write(data, resolve) + }) +} + +describe("SerializeAddon", () => { + describe("ANSI color preservation", () => { + test("should preserve text attributes (bold, italic, underline)", async () => { + const { term, addon } = createTerminal() + + const input = "\x1b[1mBOLD\x1b[0m \x1b[3mITALIC\x1b[0m \x1b[4mUNDER\x1b[0m" + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + expect(origLine!.getCell(0)!.isBold()).toBe(1) + expect(origLine!.getCell(5)!.isItalic()).toBe(1) + expect(origLine!.getCell(12)!.isUnderline()).toBe(1) + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, serialized) + + const line = term2.buffer.active.getLine(0) + + const boldCell = line!.getCell(0) + expect(boldCell!.getChars()).toBe("B") + expect(boldCell!.isBold()).toBe(1) + + const italicCell = line!.getCell(5) + expect(italicCell!.getChars()).toBe("I") + expect(italicCell!.isItalic()).toBe(1) + + const underCell = line!.getCell(12) + expect(underCell!.getChars()).toBe("U") + expect(underCell!.isUnderline()).toBe(1) + }) + + test("should preserve basic 16-color foreground colors", async () => { + const { term, addon } = createTerminal() + + const input = "\x1b[31mRED\x1b[32mGREEN\x1b[34mBLUE\x1b[0mNORMAL" + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + const origRedFg = origLine!.getCell(0)!.getFgColor() + const origGreenFg = origLine!.getCell(3)!.getFgColor() + const origBlueFg = origLine!.getCell(8)!.getFgColor() + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, serialized) + + const line = term2.buffer.active.getLine(0) + expect(line).toBeDefined() + + const redCell = line!.getCell(0) + expect(redCell!.getChars()).toBe("R") + expect(redCell!.getFgColor()).toBe(origRedFg) + + const greenCell = line!.getCell(3) + expect(greenCell!.getChars()).toBe("G") + expect(greenCell!.getFgColor()).toBe(origGreenFg) + + const blueCell = line!.getCell(8) + expect(blueCell!.getChars()).toBe("B") + expect(blueCell!.getFgColor()).toBe(origBlueFg) + }) + + test("should preserve 256-color palette colors", async () => { + const { term, addon } = createTerminal() + + const input = "\x1b[38;5;196mRED256\x1b[0mNORMAL" + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + const origRedFg = origLine!.getCell(0)!.getFgColor() + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, serialized) + + const line = term2.buffer.active.getLine(0) + const redCell = line!.getCell(0) + expect(redCell!.getChars()).toBe("R") + expect(redCell!.getFgColor()).toBe(origRedFg) + }) + + test("should preserve RGB/truecolor colors", async () => { + const { term, addon } = createTerminal() + + const input = "\x1b[38;2;255;128;64mRGB_TEXT\x1b[0mNORMAL" + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + const origRgbFg = origLine!.getCell(0)!.getFgColor() + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, serialized) + + const line = term2.buffer.active.getLine(0) + const rgbCell = line!.getCell(0) + expect(rgbCell!.getChars()).toBe("R") + expect(rgbCell!.getFgColor()).toBe(origRgbFg) + }) + + test("should preserve background colors", async () => { + const { term, addon } = createTerminal() + + const input = "\x1b[48;2;255;0;0mRED_BG\x1b[48;2;0;255;0mGREEN_BG\x1b[0mNORMAL" + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + const origRedBg = origLine!.getCell(0)!.getBgColor() + const origGreenBg = origLine!.getCell(6)!.getBgColor() + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, serialized) + + const line = term2.buffer.active.getLine(0) + + const redBgCell = line!.getCell(0) + expect(redBgCell!.getChars()).toBe("R") + expect(redBgCell!.getBgColor()).toBe(origRedBg) + + const greenBgCell = line!.getCell(6) + expect(greenBgCell!.getChars()).toBe("G") + expect(greenBgCell!.getBgColor()).toBe(origGreenBg) + }) + + test("should handle combined colors and attributes", async () => { + const { term, addon } = createTerminal() + + const input = + "\x1b[1;38;2;255;0;0;48;2;255;255;0mCOMBO\x1b[0mNORMAL " + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + const origFg = origLine!.getCell(0)!.getFgColor() + const origBg = origLine!.getCell(0)!.getBgColor() + expect(origLine!.getCell(0)!.isBold()).toBe(1) + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + const cleanSerialized = serialized.replace(/\x1b\[\d+X/g, "") + + expect(cleanSerialized.startsWith("\x1b[1;")).toBe(true) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, cleanSerialized) + + const line = term2.buffer.active.getLine(0) + const comboCell = line!.getCell(0) + + expect(comboCell!.getChars()).toBe("C") + expect(cleanSerialized).toContain("\x1b[1;38;2;255;0;0;48;2;255;255;0m") + }) + }) + + describe("round-trip serialization", () => { + test("should not produce ECH sequences", async () => { + const { term, addon } = createTerminal() + + await writeAndWait(term, "\x1b[31mHello\x1b[0m World") + + const serialized = addon.serialize() + + const hasECH = /\x1b\[\d+X/.test(serialized) + expect(hasECH).toBe(false) + }) + + test("multi-line content should not have garbage characters", async () => { + const { term, addon } = createTerminal() + + const content = [ + "\x1b[1;32m❯\x1b[0m \x1b[34mcd\x1b[0m /some/path", + "\x1b[1;32m❯\x1b[0m \x1b[34mls\x1b[0m -la", + "total 42", + ].join("\r\n") + + await writeAndWait(term, content) + + const serialized = addon.serialize() + + expect(/\x1b\[\d+X/.test(serialized)).toBe(false) + + const { term: term2 } = createTerminal() + terminals.push(term2) + await writeAndWait(term2, serialized) + + for (let row = 0; row < 3; row++) { + const line = term2.buffer.active.getLine(row)?.translateToString(true) + expect(line?.includes("𑼝")).toBe(false) + } + + expect(term2.buffer.active.getLine(0)?.translateToString(true)).toContain("cd /some/path") + expect(term2.buffer.active.getLine(1)?.translateToString(true)).toContain("ls -la") + expect(term2.buffer.active.getLine(2)?.translateToString(true)).toBe("total 42") + }) + + test("serialized output should restore after Terminal.reset()", async () => { + const { term, addon } = createTerminal() + + const content = [ + "\x1b[1;32m❯\x1b[0m \x1b[34mcd\x1b[0m /some/path", + "\x1b[1;32m❯\x1b[0m \x1b[34mls\x1b[0m -la", + "total 42", + ].join("\r\n") + + await writeAndWait(term, content) + + const serialized = addon.serialize() + + const { term: term2 } = createTerminal() + terminals.push(term2) + term2.reset() + await writeAndWait(term2, serialized) + + expect(term2.buffer.active.getLine(0)?.translateToString(true)).toContain("cd /some/path") + expect(term2.buffer.active.getLine(1)?.translateToString(true)).toContain("ls -la") + expect(term2.buffer.active.getLine(2)?.translateToString(true)).toBe("total 42") + }) + + test("alternate buffer should round-trip without garbage", async () => { + const { term, addon } = createTerminal(20, 5) + + await writeAndWait(term, "normal\r\n") + await writeAndWait(term, "\x1b[?1049h\x1b[HALT") + + expect(term.buffer.active.type).toBe("alternate") + + const serialized = addon.serialize() + + const { term: term2 } = createTerminal(20, 5) + terminals.push(term2) + await writeAndWait(term2, serialized) + + expect(term2.buffer.active.type).toBe("alternate") + + const line = term2.buffer.active.getLine(0) + expect(line?.translateToString(true)).toBe("ALT") + + // Ensure a cell beyond content isn't garbage + const cellCode = line?.getCell(10)?.getCode() + expect(cellCode === 0 || cellCode === 32).toBe(true) + }) + + test("serialized output written to new terminal should match original colors", async () => { + const { term, addon } = createTerminal(40, 5) + + const input = "\x1b[38;2;255;0;0mHello\x1b[0m \x1b[38;2;0;255;0mWorld\x1b[0m! " + await writeAndWait(term, input) + + const origLine = term.buffer.active.getLine(0) + const origHelloFg = origLine!.getCell(0)!.getFgColor() + const origWorldFg = origLine!.getCell(6)!.getFgColor() + + const serialized = addon.serialize({ range: { start: 0, end: 0 } }) + + const { term: term2 } = createTerminal(40, 5) + terminals.push(term2) + await writeAndWait(term2, serialized) + + const newLine = term2.buffer.active.getLine(0) + + expect(newLine!.getCell(0)!.getChars()).toBe("H") + expect(newLine!.getCell(0)!.getFgColor()).toBe(origHelloFg) + + expect(newLine!.getCell(6)!.getChars()).toBe("W") + expect(newLine!.getCell(6)!.getFgColor()).toBe(origWorldFg) + + expect(newLine!.getCell(11)!.getChars()).toBe("!") + }) + }) +}) diff --git a/packages/app/src/addons/serialize.ts b/packages/app/src/addons/serialize.ts new file mode 100644 index 00000000000..4309a725e51 --- /dev/null +++ b/packages/app/src/addons/serialize.ts @@ -0,0 +1,591 @@ +/** + * SerializeAddon - Serialize terminal buffer contents + * + * Port of xterm.js addon-serialize for ghostty-web. + * Enables serialization of terminal contents to a string that can + * be written back to restore terminal state. + * + * Usage: + * ```typescript + * const serializeAddon = new SerializeAddon(); + * term.loadAddon(serializeAddon); + * const content = serializeAddon.serialize(); + * ``` + */ + +import type { ITerminalAddon, ITerminalCore, IBufferRange } from "ghostty-web" + +// ============================================================================ +// Buffer Types (matching ghostty-web internal interfaces) +// ============================================================================ + +interface IBuffer { + readonly type: "normal" | "alternate" + readonly cursorX: number + readonly cursorY: number + readonly viewportY: number + readonly baseY: number + readonly length: number + getLine(y: number): IBufferLine | undefined + getNullCell(): IBufferCell +} + +interface IBufferLine { + readonly length: number + readonly isWrapped: boolean + getCell(x: number): IBufferCell | undefined + translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string +} + +interface IBufferCell { + getChars(): string + getCode(): number + getWidth(): number + getFgColorMode(): number + getBgColorMode(): number + getFgColor(): number + getBgColor(): number + isBold(): number + isItalic(): number + isUnderline(): number + isStrikethrough(): number + isBlink(): number + isInverse(): number + isInvisible(): number + isFaint(): number + isDim(): boolean +} + +// ============================================================================ +// Types +// ============================================================================ + +export interface ISerializeOptions { + /** + * The row range to serialize. When an explicit range is specified, the cursor + * will get its final repositioning. + */ + range?: ISerializeRange + /** + * The number of rows in the scrollback buffer to serialize, starting from + * the bottom of the scrollback buffer. When not specified, all available + * rows in the scrollback buffer will be serialized. + */ + scrollback?: number + /** + * Whether to exclude the terminal modes from the serialization. + * Default: false + */ + excludeModes?: boolean + /** + * Whether to exclude the alt buffer from the serialization. + * Default: false + */ + excludeAltBuffer?: boolean +} + +export interface ISerializeRange { + /** + * The line to start serializing (inclusive). + */ + start: number + /** + * The line to end serializing (inclusive). + */ + end: number +} + +export interface IHTMLSerializeOptions { + /** + * The number of rows in the scrollback buffer to serialize, starting from + * the bottom of the scrollback buffer. + */ + scrollback?: number + /** + * Whether to only serialize the selection. + * Default: false + */ + onlySelection?: boolean + /** + * Whether to include the global background of the terminal. + * Default: false + */ + includeGlobalBackground?: boolean + /** + * The range to serialize. This is prioritized over onlySelection. + */ + range?: { + startLine: number + endLine: number + startCol: number + } +} + +// ============================================================================ +// Helper Functions +// ============================================================================ + +function constrain(value: number, low: number, high: number): number { + return Math.max(low, Math.min(value, high)) +} + +function equalFg(cell1: IBufferCell, cell2: IBufferCell): boolean { + return cell1.getFgColorMode() === cell2.getFgColorMode() && cell1.getFgColor() === cell2.getFgColor() +} + +function equalBg(cell1: IBufferCell, cell2: IBufferCell): boolean { + return cell1.getBgColorMode() === cell2.getBgColorMode() && cell1.getBgColor() === cell2.getBgColor() +} + +function equalFlags(cell1: IBufferCell, cell2: IBufferCell): boolean { + return ( + !!cell1.isInverse() === !!cell2.isInverse() && + !!cell1.isBold() === !!cell2.isBold() && + !!cell1.isUnderline() === !!cell2.isUnderline() && + !!cell1.isBlink() === !!cell2.isBlink() && + !!cell1.isInvisible() === !!cell2.isInvisible() && + !!cell1.isItalic() === !!cell2.isItalic() && + !!cell1.isDim() === !!cell2.isDim() && + !!cell1.isStrikethrough() === !!cell2.isStrikethrough() + ) +} + +// ============================================================================ +// Base Serialize Handler +// ============================================================================ + +abstract class BaseSerializeHandler { + constructor(protected readonly _buffer: IBuffer) {} + + public serialize(range: IBufferRange, excludeFinalCursorPosition?: boolean): string { + let oldCell = this._buffer.getNullCell() + + const startRow = range.start.y + const endRow = range.end.y + const startColumn = range.start.x + const endColumn = range.end.x + + this._beforeSerialize(endRow - startRow + 1, startRow, endRow) + + for (let row = startRow; row <= endRow; row++) { + const line = this._buffer.getLine(row) + if (line) { + const startLineColumn = row === range.start.y ? startColumn : 0 + const endLineColumn = Math.min(endColumn, line.length) + + for (let col = startLineColumn; col < endLineColumn; col++) { + const c = line.getCell(col) + if (!c) { + continue + } + this._nextCell(c, oldCell, row, col) + oldCell = c + } + } + this._rowEnd(row, row === endRow) + } + + this._afterSerialize() + + return this._serializeString(excludeFinalCursorPosition) + } + + protected _nextCell(_cell: IBufferCell, _oldCell: IBufferCell, _row: number, _col: number): void {} + protected _rowEnd(_row: number, _isLastRow: boolean): void {} + protected _beforeSerialize(_rows: number, _startRow: number, _endRow: number): void {} + protected _afterSerialize(): void {} + protected _serializeString(_excludeFinalCursorPosition?: boolean): string { + return "" + } +} + +// ============================================================================ +// String Serialize Handler +// ============================================================================ + +class StringSerializeHandler extends BaseSerializeHandler { + private _rowIndex: number = 0 + private _allRows: string[] = [] + private _allRowSeparators: string[] = [] + private _currentRow: string = "" + private _nullCellCount: number = 0 + private _cursorStyle: IBufferCell + private _firstRow: number = 0 + private _lastCursorRow: number = 0 + private _lastCursorCol: number = 0 + private _lastContentCursorRow: number = 0 + private _lastContentCursorCol: number = 0 + + constructor( + buffer: IBuffer, + private readonly _terminal: ITerminalCore, + ) { + super(buffer) + this._cursorStyle = this._buffer.getNullCell() + } + + protected _beforeSerialize(rows: number, start: number, _end: number): void { + this._allRows = new Array(rows) + this._allRowSeparators = new Array(rows) + this._rowIndex = 0 + + this._currentRow = "" + this._nullCellCount = 0 + this._cursorStyle = this._buffer.getNullCell() + + this._lastContentCursorRow = start + this._lastCursorRow = start + this._firstRow = start + } + + protected _rowEnd(row: number, isLastRow: boolean): void { + let rowSeparator = "" + + if (this._nullCellCount > 0) { + this._currentRow += " ".repeat(this._nullCellCount) + this._nullCellCount = 0 + } + + if (!isLastRow) { + const nextLine = this._buffer.getLine(row + 1) + + if (!nextLine?.isWrapped) { + rowSeparator = "\r\n" + this._lastCursorRow = row + 1 + this._lastCursorCol = 0 + } + } + + this._allRows[this._rowIndex] = this._currentRow + this._allRowSeparators[this._rowIndex++] = rowSeparator + this._currentRow = "" + this._nullCellCount = 0 + } + + private _diffStyle(cell: IBufferCell, oldCell: IBufferCell): number[] { + const sgrSeq: number[] = [] + const fgChanged = !equalFg(cell, oldCell) + const bgChanged = !equalBg(cell, oldCell) + const flagsChanged = !equalFlags(cell, oldCell) + + if (fgChanged || bgChanged || flagsChanged) { + if (this._isAttributeDefault(cell)) { + if (!this._isAttributeDefault(oldCell)) { + sgrSeq.push(0) + } + } else { + if (flagsChanged) { + if (!!cell.isInverse() !== !!oldCell.isInverse()) { + sgrSeq.push(cell.isInverse() ? 7 : 27) + } + if (!!cell.isBold() !== !!oldCell.isBold()) { + sgrSeq.push(cell.isBold() ? 1 : 22) + } + if (!!cell.isUnderline() !== !!oldCell.isUnderline()) { + sgrSeq.push(cell.isUnderline() ? 4 : 24) + } + if (!!cell.isBlink() !== !!oldCell.isBlink()) { + sgrSeq.push(cell.isBlink() ? 5 : 25) + } + if (!!cell.isInvisible() !== !!oldCell.isInvisible()) { + sgrSeq.push(cell.isInvisible() ? 8 : 28) + } + if (!!cell.isItalic() !== !!oldCell.isItalic()) { + sgrSeq.push(cell.isItalic() ? 3 : 23) + } + if (!!cell.isDim() !== !!oldCell.isDim()) { + sgrSeq.push(cell.isDim() ? 2 : 22) + } + if (!!cell.isStrikethrough() !== !!oldCell.isStrikethrough()) { + sgrSeq.push(cell.isStrikethrough() ? 9 : 29) + } + } + if (fgChanged) { + const color = cell.getFgColor() + const mode = cell.getFgColorMode() + if (mode === 2 || mode === 3 || mode === -1) { + sgrSeq.push(38, 2, (color >>> 16) & 0xff, (color >>> 8) & 0xff, color & 0xff) + } else if (mode === 1) { + // Palette + if (color >= 16) { + sgrSeq.push(38, 5, color) + } else { + sgrSeq.push(color & 8 ? 90 + (color & 7) : 30 + (color & 7)) + } + } else { + sgrSeq.push(39) + } + } + if (bgChanged) { + const color = cell.getBgColor() + const mode = cell.getBgColorMode() + if (mode === 2 || mode === 3 || mode === -1) { + sgrSeq.push(48, 2, (color >>> 16) & 0xff, (color >>> 8) & 0xff, color & 0xff) + } else if (mode === 1) { + // Palette + if (color >= 16) { + sgrSeq.push(48, 5, color) + } else { + sgrSeq.push(color & 8 ? 100 + (color & 7) : 40 + (color & 7)) + } + } else { + sgrSeq.push(49) + } + } + } + } + + return sgrSeq + } + + private _isAttributeDefault(cell: IBufferCell): boolean { + const mode = cell.getFgColorMode() + const bgMode = cell.getBgColorMode() + + if (mode === 0 && bgMode === 0) { + return ( + !cell.isBold() && + !cell.isItalic() && + !cell.isUnderline() && + !cell.isBlink() && + !cell.isInverse() && + !cell.isInvisible() && + !cell.isDim() && + !cell.isStrikethrough() + ) + } + + const fgColor = cell.getFgColor() + const bgColor = cell.getBgColor() + const nullCell = this._buffer.getNullCell() + const nullFg = nullCell.getFgColor() + const nullBg = nullCell.getBgColor() + + return ( + fgColor === nullFg && + bgColor === nullBg && + !cell.isBold() && + !cell.isItalic() && + !cell.isUnderline() && + !cell.isBlink() && + !cell.isInverse() && + !cell.isInvisible() && + !cell.isDim() && + !cell.isStrikethrough() + ) + } + + protected _nextCell(cell: IBufferCell, _oldCell: IBufferCell, row: number, col: number): void { + const isPlaceHolderCell = cell.getWidth() === 0 + + if (isPlaceHolderCell) { + return + } + + const codepoint = cell.getCode() + const isInvalidCodepoint = codepoint > 0x10ffff || (codepoint >= 0xd800 && codepoint <= 0xdfff) + const isGarbage = isInvalidCodepoint || (codepoint >= 0xf000 && cell.getWidth() === 1) + const isEmptyCell = codepoint === 0 || cell.getChars() === "" || isGarbage + + const sgrSeq = this._diffStyle(cell, this._cursorStyle) + + const styleChanged = isEmptyCell ? !equalBg(this._cursorStyle, cell) : sgrSeq.length > 0 + + if (styleChanged) { + if (this._nullCellCount > 0) { + this._currentRow += " ".repeat(this._nullCellCount) + this._nullCellCount = 0 + } + + this._lastContentCursorRow = this._lastCursorRow = row + this._lastContentCursorCol = this._lastCursorCol = col + + this._currentRow += `\u001b[${sgrSeq.join(";")}m` + + const line = this._buffer.getLine(row) + const cellFromLine = line?.getCell(col) + if (cellFromLine) { + this._cursorStyle = cellFromLine + } + } + + if (isEmptyCell) { + this._nullCellCount += cell.getWidth() + } else { + if (this._nullCellCount > 0) { + this._currentRow += " ".repeat(this._nullCellCount) + this._nullCellCount = 0 + } + + this._currentRow += cell.getChars() + + this._lastContentCursorRow = this._lastCursorRow = row + this._lastContentCursorCol = this._lastCursorCol = col + cell.getWidth() + } + } + + protected _serializeString(excludeFinalCursorPosition?: boolean): string { + let rowEnd = this._allRows.length + + if (this._buffer.length - this._firstRow <= this._terminal.rows) { + rowEnd = this._lastContentCursorRow + 1 - this._firstRow + this._lastCursorCol = this._lastContentCursorCol + this._lastCursorRow = this._lastContentCursorRow + } + + let content = "" + + for (let i = 0; i < rowEnd; i++) { + content += this._allRows[i] + if (i + 1 < rowEnd) { + content += this._allRowSeparators[i] + } + } + + if (!excludeFinalCursorPosition) { + const absoluteCursorRow = (this._buffer.baseY ?? 0) + this._buffer.cursorY + const cursorRow = constrain(absoluteCursorRow - this._firstRow + 1, 1, Number.MAX_SAFE_INTEGER) + const cursorCol = this._buffer.cursorX + 1 + content += `\u001b[${cursorRow};${cursorCol}H` + } + + return content + } +} + +// ============================================================================ +// SerializeAddon Class +// ============================================================================ + +export class SerializeAddon implements ITerminalAddon { + private _terminal?: ITerminalCore + + /** + * Activate the addon (called by Terminal.loadAddon) + */ + public activate(terminal: ITerminalCore): void { + this._terminal = terminal + } + + /** + * Dispose the addon and clean up resources + */ + public dispose(): void { + this._terminal = undefined + } + + /** + * Serializes terminal rows into a string that can be written back to the + * terminal to restore the state. The cursor will also be positioned to the + * correct cell. + * + * @param options Custom options to allow control over what gets serialized. + */ + public serialize(options?: ISerializeOptions): string { + if (!this._terminal) { + throw new Error("Cannot use addon until it has been loaded") + } + + const terminal = this._terminal as any + const buffer = terminal.buffer + + if (!buffer) { + return "" + } + + const normalBuffer = buffer.normal || buffer.active + const altBuffer = buffer.alternate + + if (!normalBuffer) { + return "" + } + + let content = options?.range + ? this._serializeBufferByRange(normalBuffer, options.range, true) + : this._serializeBufferByScrollback(normalBuffer, options?.scrollback) + + if (!options?.excludeAltBuffer && buffer.active?.type === "alternate" && altBuffer) { + const alternateContent = this._serializeBufferByScrollback(altBuffer, undefined) + content += `\u001b[?1049h\u001b[H${alternateContent}` + } + + return content + } + + /** + * Serializes terminal content as plain text (no escape sequences) + * @param options Custom options to allow control over what gets serialized. + */ + public serializeAsText(options?: { scrollback?: number; trimWhitespace?: boolean }): string { + if (!this._terminal) { + throw new Error("Cannot use addon until it has been loaded") + } + + const terminal = this._terminal as any + const buffer = terminal.buffer + + if (!buffer) { + return "" + } + + const activeBuffer = buffer.active || buffer.normal + if (!activeBuffer) { + return "" + } + + const maxRows = activeBuffer.length + const scrollback = options?.scrollback + const correctRows = scrollback === undefined ? maxRows : constrain(scrollback + this._terminal.rows, 0, maxRows) + + const startRow = maxRows - correctRows + const endRow = maxRows - 1 + const lines: string[] = [] + + for (let row = startRow; row <= endRow; row++) { + const line = activeBuffer.getLine(row) + if (line) { + const text = line.translateToString(options?.trimWhitespace ?? true) + lines.push(text) + } + } + + // Trim trailing empty lines if requested + if (options?.trimWhitespace) { + while (lines.length > 0 && lines[lines.length - 1] === "") { + lines.pop() + } + } + + return lines.join("\n") + } + + private _serializeBufferByScrollback(buffer: IBuffer, scrollback?: number): string { + const maxRows = buffer.length + const rows = this._terminal?.rows ?? 24 + const correctRows = scrollback === undefined ? maxRows : constrain(scrollback + rows, 0, maxRows) + return this._serializeBufferByRange( + buffer, + { + start: maxRows - correctRows, + end: maxRows - 1, + }, + false, + ) + } + + private _serializeBufferByRange( + buffer: IBuffer, + range: ISerializeRange, + excludeFinalCursorPosition: boolean, + ): string { + const handler = new StringSerializeHandler(buffer, this._terminal!) + const cols = this._terminal?.cols ?? 80 + return handler.serialize( + { + start: { x: 0, y: range.start }, + end: { x: cols, y: range.end }, + }, + excludeFinalCursorPosition, + ) + } +} diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx new file mode 100644 index 00000000000..1c82439d4d7 --- /dev/null +++ b/packages/app/src/app.tsx @@ -0,0 +1,149 @@ +import "@/index.css" +import { ErrorBoundary, Show, lazy, type ParentProps } from "solid-js" +import { Router, Route, Navigate } from "@solidjs/router" +import { MetaProvider } from "@solidjs/meta" +import { Font } from "@opencode-ai/ui/font" +import { MarkedProvider } from "@opencode-ai/ui/context/marked" +import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" +import { CodeComponentProvider } from "@opencode-ai/ui/context/code" +import { I18nProvider } from "@opencode-ai/ui/context" +import { Diff } from "@opencode-ai/ui/diff" +import { Code } from "@opencode-ai/ui/code" +import { ThemeProvider } from "@opencode-ai/ui/theme" +import { GlobalSyncProvider } from "@/context/global-sync" +import { PermissionProvider } from "@/context/permission" +import { LayoutProvider } from "@/context/layout" +import { GlobalSDKProvider } from "@/context/global-sdk" +import { ServerProvider, useServer } from "@/context/server" +import { SettingsProvider } from "@/context/settings" +import { TerminalProvider } from "@/context/terminal" +import { PromptProvider } from "@/context/prompt" +import { FileProvider } from "@/context/file" +import { NotificationProvider } from "@/context/notification" +import { DialogProvider } from "@opencode-ai/ui/context/dialog" +import { CommandProvider } from "@/context/command" +import { LanguageProvider, useLanguage } from "@/context/language" +import { usePlatform } from "@/context/platform" +import { Logo } from "@opencode-ai/ui/logo" +import Layout from "@/pages/layout" +import DirectoryLayout from "@/pages/directory-layout" +import { ErrorPage } from "./pages/error" +import { iife } from "@opencode-ai/util/iife" +import { Suspense } from "solid-js" + +const Home = lazy(() => import("@/pages/home")) +const Session = lazy(() => import("@/pages/session")) +const Loading = () =>
+ +function UiI18nBridge(props: ParentProps) { + const language = useLanguage() + return {props.children} +} + +declare global { + interface Window { + __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string } + } +} + +function MarkedProviderWithNativeParser(props: ParentProps) { + const platform = usePlatform() + return {props.children} +} + +export function AppBaseProviders(props: ParentProps) { + return ( + + + + + + }> + + + + {props.children} + + + + + + + + + ) +} + +function ServerKey(props: ParentProps) { + const server = useServer() + return ( + + {props.children} + + ) +} + +export function AppInterface(props: { defaultUrl?: string }) { + const defaultServerUrl = () => { + if (props.defaultUrl) return props.defaultUrl + if (location.hostname.includes("opencode.ai")) return "http://localhost:4096" + if (import.meta.env.DEV) + return `http://${import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "localhost"}:${import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"}` + + return window.location.origin + } + + return ( + + + + + ( + + + + + + {props.children} + + + + + + )} + > + ( + }> + + + )} + /> + + } /> + ( + + + + + }> + + + + + + + )} + /> + + + + + + + ) +} diff --git a/packages/app/src/components/dialog-connect-provider.tsx b/packages/app/src/components/dialog-connect-provider.tsx new file mode 100644 index 00000000000..be33cba75fc --- /dev/null +++ b/packages/app/src/components/dialog-connect-provider.tsx @@ -0,0 +1,425 @@ +import type { ProviderAuthAuthorization } from "@opencode-ai/sdk/v2/client" +import { Button } from "@opencode-ai/ui/button" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import type { IconName } from "@opencode-ai/ui/icons/provider" +import { List, type ListRef } from "@opencode-ai/ui/list" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { Spinner } from "@opencode-ai/ui/spinner" +import { TextField } from "@opencode-ai/ui/text-field" +import { showToast } from "@opencode-ai/ui/toast" +import { iife } from "@opencode-ai/util/iife" +import { createMemo, Match, onCleanup, onMount, Switch } from "solid-js" +import { createStore, produce } from "solid-js/store" +import { Link } from "@/components/link" +import { useLanguage } from "@/context/language" +import { useGlobalSDK } from "@/context/global-sdk" +import { useGlobalSync } from "@/context/global-sync" +import { usePlatform } from "@/context/platform" +import { DialogSelectModel } from "./dialog-select-model" +import { DialogSelectProvider } from "./dialog-select-provider" + +export function DialogConnectProvider(props: { provider: string }) { + const dialog = useDialog() + const globalSync = useGlobalSync() + const globalSDK = useGlobalSDK() + const platform = usePlatform() + const language = useLanguage() + const provider = createMemo(() => globalSync.data.provider.all.find((x) => x.id === props.provider)!) + const methods = createMemo( + () => + globalSync.data.provider_auth[props.provider] ?? [ + { + type: "api", + label: language.t("provider.connect.method.apiKey"), + }, + ], + ) + const [store, setStore] = createStore({ + methodIndex: undefined as undefined | number, + authorization: undefined as undefined | ProviderAuthAuthorization, + state: "pending" as undefined | "pending" | "complete" | "error", + error: undefined as string | undefined, + }) + + const method = createMemo(() => (store.methodIndex !== undefined ? methods().at(store.methodIndex!) : undefined)) + + const methodLabel = (value?: { type?: string; label?: string }) => { + if (!value) return "" + if (value.type === "api") return language.t("provider.connect.method.apiKey") + return value.label ?? "" + } + + async function selectMethod(index: number) { + const method = methods()[index] + setStore( + produce((draft) => { + draft.methodIndex = index + draft.authorization = undefined + draft.state = undefined + draft.error = undefined + }), + ) + + if (method.type === "oauth") { + setStore("state", "pending") + const start = Date.now() + await globalSDK.client.provider.oauth + .authorize( + { + providerID: props.provider, + method: index, + }, + { throwOnError: true }, + ) + .then((x) => { + const elapsed = Date.now() - start + const delay = 1000 - elapsed + + if (delay > 0) { + setTimeout(() => { + setStore("state", "complete") + setStore("authorization", x.data!) + }, delay) + return + } + setStore("state", "complete") + setStore("authorization", x.data!) + }) + .catch((e) => { + setStore("state", "error") + setStore("error", String(e)) + }) + } + } + + let listRef: ListRef | undefined + function handleKey(e: KeyboardEvent) { + if (e.key === "Enter" && e.target instanceof HTMLInputElement) { + return + } + if (e.key === "Escape") return + listRef?.onKeyDown(e) + } + + onMount(() => { + if (methods().length === 1) { + selectMethod(0) + } + document.addEventListener("keydown", handleKey) + onCleanup(() => { + document.removeEventListener("keydown", handleKey) + }) + }) + + async function complete() { + await globalSDK.client.global.dispose() + dialog.close() + showToast({ + variant: "success", + icon: "circle-check", + title: language.t("provider.connect.toast.connected.title", { provider: provider().name }), + description: language.t("provider.connect.toast.connected.description", { provider: provider().name }), + }) + } + + function goBack() { + if (methods().length === 1) { + dialog.show(() => ) + return + } + if (store.authorization) { + setStore("authorization", undefined) + setStore("methodIndex", undefined) + return + } + if (store.methodIndex) { + setStore("methodIndex", undefined) + return + } + dialog.show(() => ) + } + + return ( + + } + > +
+
+ +
+ + + {language.t("provider.connect.title.anthropicProMax")} + + {language.t("provider.connect.title", { provider: provider().name })} + +
+
+
+ + +
+ {language.t("provider.connect.selectMethod", { provider: provider().name })} +
+
+ { + listRef = ref + }} + items={methods} + key={(m) => m?.label} + onSelect={async (method, index) => { + if (!method) return + selectMethod(index) + }} + > + {(i) => ( +
+
+ + {methodLabel(i)} +
+ )} + +
+ + +
+
+ + {language.t("provider.connect.status.inProgress")} +
+
+
+ +
+
+ + {language.t("provider.connect.status.failed", { error: store.error ?? "" })} +
+
+
+ + {iife(() => { + const [formStore, setFormStore] = createStore({ + value: "", + error: undefined as string | undefined, + }) + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + + const form = e.currentTarget as HTMLFormElement + const formData = new FormData(form) + const apiKey = formData.get("apiKey") as string + + if (!apiKey?.trim()) { + setFormStore("error", language.t("provider.connect.apiKey.required")) + return + } + + setFormStore("error", undefined) + await globalSDK.client.auth.set({ + providerID: props.provider, + auth: { + type: "api", + key: apiKey, + }, + }) + await complete() + } + + return ( +
+ + +
+
+ {language.t("provider.connect.opencodeZen.line1")} +
+
+ {language.t("provider.connect.opencodeZen.line2")} +
+
+ {language.t("provider.connect.opencodeZen.visit.prefix")} + + {language.t("provider.connect.opencodeZen.visit.link")} + + {language.t("provider.connect.opencodeZen.visit.suffix")} +
+
+
+ +
+ {language.t("provider.connect.apiKey.description", { provider: provider().name })} +
+
+
+
+ + + +
+ ) + })} +
+ + + + {iife(() => { + const [formStore, setFormStore] = createStore({ + value: "", + error: undefined as string | undefined, + }) + + onMount(() => { + if (store.authorization?.method === "code" && store.authorization?.url) { + platform.openLink(store.authorization.url) + } + }) + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + + const form = e.currentTarget as HTMLFormElement + const formData = new FormData(form) + const code = formData.get("code") as string + + if (!code?.trim()) { + setFormStore("error", language.t("provider.connect.oauth.code.required")) + return + } + + setFormStore("error", undefined) + const result = await globalSDK.client.provider.oauth + .callback({ + providerID: props.provider, + method: store.methodIndex, + code, + }) + .then((value) => + value.error ? { ok: false as const, error: value.error } : { ok: true as const }, + ) + .catch((error) => ({ ok: false as const, error })) + if (result.ok) { + await complete() + return + } + const message = result.error instanceof Error ? result.error.message : String(result.error) + setFormStore("error", message || language.t("provider.connect.oauth.code.invalid")) + } + + return ( +
+
+ {language.t("provider.connect.oauth.code.visit.prefix")} + + {language.t("provider.connect.oauth.code.visit.link")} + + {language.t("provider.connect.oauth.code.visit.suffix", { provider: provider().name })} +
+
+ + + +
+ ) + })} +
+ + {iife(() => { + const code = createMemo(() => { + const instructions = store.authorization?.instructions + if (instructions?.includes(":")) { + return instructions?.split(":")[1]?.trim() + } + return instructions + }) + + onMount(async () => { + const result = await globalSDK.client.provider.oauth + .callback({ + providerID: props.provider, + method: store.methodIndex, + }) + .then((value) => + value.error ? { ok: false as const, error: value.error } : { ok: true as const }, + ) + .catch((error) => ({ ok: false as const, error })) + if (!result.ok) { + const message = result.error instanceof Error ? result.error.message : String(result.error) + setStore("state", "error") + setStore("error", message) + return + } + await complete() + }) + + return ( +
+
+ {language.t("provider.connect.oauth.auto.visit.prefix")} + + {language.t("provider.connect.oauth.auto.visit.link")} + + {language.t("provider.connect.oauth.auto.visit.suffix", { provider: provider().name })} +
+ +
+ + {language.t("provider.connect.status.waiting")} +
+
+ ) + })} +
+
+
+ +
+
+
+ ) +} diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx new file mode 100644 index 00000000000..7664470f73b --- /dev/null +++ b/packages/app/src/components/dialog-edit-project.tsx @@ -0,0 +1,246 @@ +import { Button } from "@opencode-ai/ui/button" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { TextField } from "@opencode-ai/ui/text-field" +import { Icon } from "@opencode-ai/ui/icon" +import { createMemo, createSignal, For, Show } from "solid-js" +import { createStore } from "solid-js/store" +import { useGlobalSDK } from "@/context/global-sdk" +import { type LocalProject, getAvatarColors } from "@/context/layout" +import { getFilename } from "@opencode-ai/util/path" +import { Avatar } from "@opencode-ai/ui/avatar" +import { useLanguage } from "@/context/language" + +const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const + +export function DialogEditProject(props: { project: LocalProject }) { + const dialog = useDialog() + const globalSDK = useGlobalSDK() + const language = useLanguage() + + const folderName = createMemo(() => getFilename(props.project.worktree)) + const defaultName = createMemo(() => props.project.name || folderName()) + + const [store, setStore] = createStore({ + name: defaultName(), + color: props.project.icon?.color || "pink", + iconUrl: props.project.icon?.override || "", + startup: props.project.commands?.start ?? "", + saving: false, + }) + + const [dragOver, setDragOver] = createSignal(false) + const [iconHover, setIconHover] = createSignal(false) + + function handleFileSelect(file: File) { + if (!file.type.startsWith("image/")) return + const reader = new FileReader() + reader.onload = (e) => { + setStore("iconUrl", e.target?.result as string) + setIconHover(false) + } + reader.readAsDataURL(file) + } + + function handleDrop(e: DragEvent) { + e.preventDefault() + setDragOver(false) + const file = e.dataTransfer?.files[0] + if (file) handleFileSelect(file) + } + + function handleDragOver(e: DragEvent) { + e.preventDefault() + setDragOver(true) + } + + function handleDragLeave() { + setDragOver(false) + } + + function handleInputChange(e: Event) { + const input = e.target as HTMLInputElement + const file = input.files?.[0] + if (file) handleFileSelect(file) + } + + function clearIcon() { + setStore("iconUrl", "") + } + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + + if (!props.project.id) return + + setStore("saving", true) + const name = store.name.trim() === folderName() ? "" : store.name.trim() + const start = store.startup.trim() + await globalSDK.client.project.update({ + projectID: props.project.id, + directory: props.project.worktree, + name, + icon: { color: store.color, override: store.iconUrl }, + commands: { start }, + }) + setStore("saving", false) + dialog.close() + } + + return ( + +
+
+ setStore("name", v)} + /> + +
+ +
+
setIconHover(true)} onMouseLeave={() => setIconHover(false)}> +
{ + if (store.iconUrl && iconHover()) { + clearIcon() + } else { + document.getElementById("icon-upload")?.click() + } + }} + > + + +
+ } + > + {language.t("dialog.project.edit.icon.alt")} + +
+
+ +
+
+ +
+
+ +
+ {language.t("dialog.project.edit.icon.hint")} + {language.t("dialog.project.edit.icon.recommended")} +
+
+
+ + +
+ +
+ + {(color) => ( + + )} + +
+
+
+ + setStore("startup", v)} + spellcheck={false} + class="max-h-40 w-full font-mono text-xs no-scrollbar" + /> +
+ +
+ + +
+ + + ) +} diff --git a/packages/app/src/components/dialog-fork.tsx b/packages/app/src/components/dialog-fork.tsx new file mode 100644 index 00000000000..17782f5ab8d --- /dev/null +++ b/packages/app/src/components/dialog-fork.tsx @@ -0,0 +1,104 @@ +import { Component, createMemo } from "solid-js" +import { useNavigate, useParams } from "@solidjs/router" +import { useSync } from "@/context/sync" +import { useSDK } from "@/context/sdk" +import { usePrompt } from "@/context/prompt" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { extractPromptFromParts } from "@/utils/prompt" +import type { TextPart as SDKTextPart } from "@opencode-ai/sdk/v2/client" +import { base64Encode } from "@opencode-ai/util/encode" +import { useLanguage } from "@/context/language" + +interface ForkableMessage { + id: string + text: string + time: string +} + +function formatTime(date: Date): string { + return date.toLocaleTimeString(undefined, { timeStyle: "short" }) +} + +export const DialogFork: Component = () => { + const params = useParams() + const navigate = useNavigate() + const sync = useSync() + const sdk = useSDK() + const prompt = usePrompt() + const dialog = useDialog() + const language = useLanguage() + + const messages = createMemo((): ForkableMessage[] => { + const sessionID = params.id + if (!sessionID) return [] + + const msgs = sync.data.message[sessionID] ?? [] + const result: ForkableMessage[] = [] + + for (const message of msgs) { + if (message.role !== "user") continue + + const parts = sync.data.part[message.id] ?? [] + const textPart = parts.find((x): x is SDKTextPart => x.type === "text" && !x.synthetic && !x.ignored) + if (!textPart) continue + + result.push({ + id: message.id, + text: textPart.text.replace(/\n/g, " ").slice(0, 200), + time: formatTime(new Date(message.time.created)), + }) + } + + return result.reverse() + }) + + const handleSelect = (item: ForkableMessage | undefined) => { + if (!item) return + + const sessionID = params.id + if (!sessionID) return + + const parts = sync.data.part[item.id] ?? [] + const restored = extractPromptFromParts(parts, { + directory: sdk.directory, + attachmentName: language.t("common.attachment"), + }) + + dialog.close() + + sdk.client.session.fork({ sessionID, messageID: item.id }).then((forked) => { + if (!forked.data) return + navigate(`/${base64Encode(sdk.directory)}/session/${forked.data.id}`) + requestAnimationFrame(() => { + prompt.set(restored) + }) + }) + } + + return ( + + x.id} + items={messages} + filterKeys={["text"]} + onSelect={handleSelect} + > + {(item) => ( +
+ + {item.text} + + + {item.time} + +
+ )} +
+
+ ) +} diff --git a/packages/app/src/components/dialog-manage-models.tsx b/packages/app/src/components/dialog-manage-models.tsx new file mode 100644 index 00000000000..1ecefa2cbbf --- /dev/null +++ b/packages/app/src/components/dialog-manage-models.tsx @@ -0,0 +1,59 @@ +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { Switch } from "@opencode-ai/ui/switch" +import type { Component } from "solid-js" +import { useLocal } from "@/context/local" +import { popularProviders } from "@/hooks/use-providers" +import { useLanguage } from "@/context/language" + +export const DialogManageModels: Component = () => { + const local = useLocal() + const language = useLanguage() + return ( + + `${x?.provider?.id}:${x?.id}`} + items={local.model.list()} + filterKeys={["provider.name", "name", "id"]} + sortBy={(a, b) => a.name.localeCompare(b.name)} + groupBy={(x) => x.provider.name} + sortGroupsBy={(a, b) => { + const aProvider = a.items[0].provider.id + const bProvider = b.items[0].provider.id + if (popularProviders.includes(aProvider) && !popularProviders.includes(bProvider)) return -1 + if (!popularProviders.includes(aProvider) && popularProviders.includes(bProvider)) return 1 + return popularProviders.indexOf(aProvider) - popularProviders.indexOf(bProvider) + }} + onSelect={(x) => { + if (!x) return + const visible = local.model.visible({ + modelID: x.id, + providerID: x.provider.id, + }) + local.model.setVisibility({ modelID: x.id, providerID: x.provider.id }, !visible) + }} + > + {(i) => ( +
+ {i.name} +
e.stopPropagation()}> + { + local.model.setVisibility({ modelID: i.id, providerID: i.provider.id }, checked) + }} + /> +
+
+ )} +
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-directory.tsx b/packages/app/src/components/dialog-select-directory.tsx new file mode 100644 index 00000000000..1ee2501de5f --- /dev/null +++ b/packages/app/src/components/dialog-select-directory.tsx @@ -0,0 +1,117 @@ +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { FileIcon } from "@opencode-ai/ui/file-icon" +import { List } from "@opencode-ai/ui/list" +import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { createMemo } from "solid-js" +import { useGlobalSDK } from "@/context/global-sdk" +import { useGlobalSync } from "@/context/global-sync" +import { useLanguage } from "@/context/language" + +interface DialogSelectDirectoryProps { + title?: string + multiple?: boolean + onSelect: (result: string | string[] | null) => void +} + +export function DialogSelectDirectory(props: DialogSelectDirectoryProps) { + const sync = useGlobalSync() + const sdk = useGlobalSDK() + const dialog = useDialog() + const language = useLanguage() + + const home = createMemo(() => sync.data.path.home) + const root = createMemo(() => sync.data.path.home || sync.data.path.directory) + + function join(base: string | undefined, rel: string) { + const b = (base ?? "").replace(/[\\/]+$/, "") + const r = rel.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "") + if (!b) return r + if (!r) return b + return b + "/" + r + } + + function display(rel: string) { + const full = join(root(), rel) + const h = home() + if (!h) return full + if (full === h) return "~" + if (full.startsWith(h + "/") || full.startsWith(h + "\\")) { + return "~" + full.slice(h.length) + } + return full + } + + function normalizeQuery(query: string) { + const h = home() + + if (!query) return query + if (query.startsWith("~/")) return query.slice(2) + + if (h) { + const lc = query.toLowerCase() + const hc = h.toLowerCase() + if (lc === hc || lc.startsWith(hc + "/") || lc.startsWith(hc + "\\")) { + return query.slice(h.length).replace(/^[\\/]+/, "") + } + } + + return query + } + + async function fetchDirs(query: string) { + const directory = root() + if (!directory) return [] as string[] + + const results = await sdk.client.find + .files({ directory, query, type: "directory", limit: 50 }) + .then((x) => x.data ?? []) + .catch(() => []) + + return results.map((x) => x.replace(/[\\/]+$/, "")) + } + + const directories = async (filter: string) => { + const query = normalizeQuery(filter.trim()) + return fetchDirs(query) + } + + function resolve(rel: string) { + const absolute = join(root(), rel) + props.onSelect(props.multiple ? [absolute] : absolute) + dialog.close() + } + + return ( + + x} + onSelect={(path) => { + if (!path) return + resolve(path) + }} + > + {(rel) => { + const path = display(rel) + return ( +
+
+ +
+ + {getDirectory(path)} + + {getFilename(path)} +
+
+
+ ) + }} +
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx new file mode 100644 index 00000000000..7c3113a544e --- /dev/null +++ b/packages/app/src/components/dialog-select-file.tsx @@ -0,0 +1,196 @@ +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { FileIcon } from "@opencode-ai/ui/file-icon" +import { Keybind } from "@opencode-ai/ui/keybind" +import { List } from "@opencode-ai/ui/list" +import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { useParams } from "@solidjs/router" +import { createMemo, createSignal, onCleanup, Show } from "solid-js" +import { formatKeybind, useCommand, type CommandOption } from "@/context/command" +import { useLayout } from "@/context/layout" +import { useFile } from "@/context/file" +import { useLanguage } from "@/context/language" + +type EntryType = "command" | "file" + +type Entry = { + id: string + type: EntryType + title: string + description?: string + keybind?: string + category: string + option?: CommandOption + path?: string +} + +export function DialogSelectFile() { + const command = useCommand() + const language = useLanguage() + const layout = useLayout() + const file = useFile() + const dialog = useDialog() + const params = useParams() + const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) + const tabs = createMemo(() => layout.tabs(sessionKey())) + const view = createMemo(() => layout.view(sessionKey())) + const state = { cleanup: undefined as (() => void) | void, committed: false } + const [grouped, setGrouped] = createSignal(false) + const common = [ + "session.new", + "workspace.new", + "session.previous", + "session.next", + "terminal.toggle", + "review.toggle", + ] + const limit = 5 + + const allowed = createMemo(() => + command.options.filter( + (option) => !option.disabled && !option.id.startsWith("suggested.") && option.id !== "file.open", + ), + ) + + const commandItem = (option: CommandOption): Entry => ({ + id: "command:" + option.id, + type: "command", + title: option.title, + description: option.description, + keybind: option.keybind, + category: language.t("palette.group.commands"), + option, + }) + + const fileItem = (path: string): Entry => ({ + id: "file:" + path, + type: "file", + title: path, + category: language.t("palette.group.files"), + path, + }) + + const list = createMemo(() => allowed().map(commandItem)) + + const picks = createMemo(() => { + const all = allowed() + const order = new Map(common.map((id, index) => [id, index])) + const picked = all.filter((option) => order.has(option.id)) + const base = picked.length ? picked : all.slice(0, limit) + const sorted = picked.length ? [...base].sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)) : base + return sorted.map(commandItem) + }) + + const recent = createMemo(() => { + const all = tabs().all() + const active = tabs().active() + const order = active ? [active, ...all.filter((item) => item !== active)] : all + const seen = new Set() + const items: Entry[] = [] + + for (const item of order) { + const path = file.pathFromTab(item) + if (!path) continue + if (seen.has(path)) continue + seen.add(path) + items.push(fileItem(path)) + } + + return items.slice(0, limit) + }) + + const items = async (filter: string) => { + const query = filter.trim() + setGrouped(query.length > 0) + if (!query) return [...picks(), ...recent()] + const files = await file.searchFiles(query) + const entries = files.map(fileItem) + return [...list(), ...entries] + } + + const handleMove = (item: Entry | undefined) => { + state.cleanup?.() + if (!item) return + if (item.type !== "command") return + state.cleanup = item.option?.onHighlight?.() + } + + const open = (path: string) => { + const value = file.tab(path) + tabs().open(value) + file.load(path) + view().reviewPanel.open() + } + + const handleSelect = (item: Entry | undefined) => { + if (!item) return + state.committed = true + state.cleanup = undefined + dialog.close() + + if (item.type === "command") { + item.option?.onSelect?.("palette") + return + } + + if (!item.path) return + open(item.path) + } + + onCleanup(() => { + if (state.committed) return + state.cleanup?.() + }) + + return ( + + item.id} + filterKeys={["title", "description", "category"]} + groupBy={(item) => item.category} + onMove={handleMove} + onSelect={handleSelect} + > + {(item) => ( + +
+ +
+ + {getDirectory(item.path ?? "")} + + {getFilename(item.path ?? "")} +
+
+ + } + > +
+
+ {item.title} + + {item.description} + +
+ + {formatKeybind(item.keybind ?? "")} + +
+
+ )} +
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-mcp.tsx b/packages/app/src/components/dialog-select-mcp.tsx new file mode 100644 index 00000000000..8eb08878912 --- /dev/null +++ b/packages/app/src/components/dialog-select-mcp.tsx @@ -0,0 +1,96 @@ +import { Component, createMemo, createSignal, Show } from "solid-js" +import { useSync } from "@/context/sync" +import { useSDK } from "@/context/sdk" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { Switch } from "@opencode-ai/ui/switch" +import { useLanguage } from "@/context/language" + +export const DialogSelectMcp: Component = () => { + const sync = useSync() + const sdk = useSDK() + const language = useLanguage() + const [loading, setLoading] = createSignal(null) + + const items = createMemo(() => + Object.entries(sync.data.mcp ?? {}) + .map(([name, status]) => ({ name, status: status.status })) + .sort((a, b) => a.name.localeCompare(b.name)), + ) + + const toggle = async (name: string) => { + if (loading()) return + setLoading(name) + const status = sync.data.mcp[name] + if (status?.status === "connected") { + await sdk.client.mcp.disconnect({ name }) + } else { + await sdk.client.mcp.connect({ name }) + } + const result = await sdk.client.mcp.status() + if (result.data) sync.set("mcp", result.data) + setLoading(null) + } + + const enabledCount = createMemo(() => items().filter((i) => i.status === "connected").length) + const totalCount = createMemo(() => items().length) + + return ( + + x?.name ?? ""} + items={items} + filterKeys={["name", "status"]} + sortBy={(a, b) => a.name.localeCompare(b.name)} + onSelect={(x) => { + if (x) toggle(x.name) + }} + > + {(i) => { + const mcpStatus = () => sync.data.mcp[i.name] + const status = () => mcpStatus()?.status + const error = () => { + const s = mcpStatus() + return s?.status === "failed" ? s.error : undefined + } + const enabled = () => status() === "connected" + return ( +
+
+
+ {i.name} + + {language.t("mcp.status.connected")} + + + {language.t("mcp.status.failed")} + + + {language.t("mcp.status.needs_auth")} + + + {language.t("mcp.status.disabled")} + + + {language.t("common.loading.ellipsis")} + +
+ + {error()} + +
+
e.stopPropagation()}> + toggle(i.name)} /> +
+
+ ) + }} +
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-model-unpaid.tsx b/packages/app/src/components/dialog-select-model-unpaid.tsx new file mode 100644 index 00000000000..1e7c9f52a9a --- /dev/null +++ b/packages/app/src/components/dialog-select-model-unpaid.tsx @@ -0,0 +1,130 @@ +import { Button } from "@opencode-ai/ui/button" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import type { IconName } from "@opencode-ai/ui/icons/provider" +import { List, type ListRef } from "@opencode-ai/ui/list" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { Tag } from "@opencode-ai/ui/tag" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { type Component, onCleanup, onMount, Show } from "solid-js" +import { useLocal } from "@/context/local" +import { popularProviders, useProviders } from "@/hooks/use-providers" +import { DialogConnectProvider } from "./dialog-connect-provider" +import { DialogSelectProvider } from "./dialog-select-provider" +import { ModelTooltip } from "./model-tooltip" +import { useLanguage } from "@/context/language" + +export const DialogSelectModelUnpaid: Component = () => { + const local = useLocal() + const dialog = useDialog() + const providers = useProviders() + const language = useLanguage() + + let listRef: ListRef | undefined + const handleKey = (e: KeyboardEvent) => { + if (e.key === "Escape") return + listRef?.onKeyDown(e) + } + + onMount(() => { + document.addEventListener("keydown", handleKey) + onCleanup(() => { + document.removeEventListener("keydown", handleKey) + }) + }) + + return ( + +
+
{language.t("dialog.model.unpaid.freeModels.title")}
+ (listRef = ref)} + items={local.model.list} + current={local.model.current()} + key={(x) => `${x.provider.id}:${x.id}`} + itemWrapper={(item, node) => ( + + } + > + {node} + + )} + onSelect={(x) => { + local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { + recent: true, + }) + dialog.close() + }} + > + {(i) => ( +
+ {i.name} + {language.t("model.tag.free")} + + {language.t("model.tag.latest")} + +
+ )} +
+
+
+
+
+
+
+
{language.t("dialog.model.unpaid.addMore.title")}
+
+ x?.id} + items={providers.popular} + activeIcon="plus-small" + sortBy={(a, b) => { + if (popularProviders.includes(a.id) && popularProviders.includes(b.id)) + return popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id) + return a.name.localeCompare(b.name) + }} + onSelect={(x) => { + if (!x) return + dialog.show(() => ) + }} + > + {(i) => ( +
+ + {i.name} + + {language.t("dialog.provider.tag.recommended")} + + +
{language.t("dialog.provider.anthropic.note")}
+
+
+ )} +
+ +
+
+
+
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-model.tsx b/packages/app/src/components/dialog-select-model.tsx new file mode 100644 index 00000000000..5569d7780fe --- /dev/null +++ b/packages/app/src/components/dialog-select-model.tsx @@ -0,0 +1,162 @@ +import { Popover as Kobalte } from "@kobalte/core/popover" +import { Component, ComponentProps, createMemo, createSignal, JSX, Show, ValidComponent } from "solid-js" +import { useLocal } from "@/context/local" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { popularProviders } from "@/hooks/use-providers" +import { Button } from "@opencode-ai/ui/button" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Tag } from "@opencode-ai/ui/tag" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { DialogSelectProvider } from "./dialog-select-provider" +import { DialogManageModels } from "./dialog-manage-models" +import { ModelTooltip } from "./model-tooltip" +import { useLanguage } from "@/context/language" + +const ModelList: Component<{ + provider?: string + class?: string + onSelect: () => void + action?: JSX.Element +}> = (props) => { + const local = useLocal() + const language = useLanguage() + + const models = createMemo(() => + local.model + .list() + .filter((m) => local.model.visible({ modelID: m.id, providerID: m.provider.id })) + .filter((m) => (props.provider ? m.provider.id === props.provider : true)), + ) + + return ( + `${x.provider.id}:${x.id}`} + items={models} + current={local.model.current()} + filterKeys={["provider.name", "name", "id"]} + sortBy={(a, b) => a.name.localeCompare(b.name)} + groupBy={(x) => x.provider.name} + sortGroupsBy={(a, b) => { + const aProvider = a.items[0].provider.id + const bProvider = b.items[0].provider.id + if (popularProviders.includes(aProvider) && !popularProviders.includes(bProvider)) return -1 + if (!popularProviders.includes(aProvider) && popularProviders.includes(bProvider)) return 1 + return popularProviders.indexOf(aProvider) - popularProviders.indexOf(bProvider) + }} + itemWrapper={(item, node) => ( + + } + > + {node} + + )} + onSelect={(x) => { + local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { + recent: true, + }) + props.onSelect() + }} + > + {(i) => ( +
+ {i.name} + + {language.t("model.tag.free")} + + + {language.t("model.tag.latest")} + +
+ )} +
+ ) +} + +export function ModelSelectorPopover(props: { + provider?: string + children?: JSX.Element + triggerAs?: T + triggerProps?: ComponentProps +}) { + const [open, setOpen] = createSignal(false) + const dialog = useDialog() + + const handleManage = () => { + setOpen(false) + dialog.show(() => ) + } + const language = useLanguage() + + return ( + + + {props.children} + + + + {language.t("dialog.model.select.title")} + setOpen(false)} + class="p-1" + action={ + + } + /> + + + + ) +} + +export const DialogSelectModel: Component<{ provider?: string }> = (props) => { + const dialog = useDialog() + const language = useLanguage() + + return ( + dialog.show(() => )} + > + {language.t("command.provider.connect")} + + } + > + dialog.close()} /> + + + ) +} diff --git a/packages/app/src/components/dialog-select-provider.tsx b/packages/app/src/components/dialog-select-provider.tsx new file mode 100644 index 00000000000..1e059c21983 --- /dev/null +++ b/packages/app/src/components/dialog-select-provider.tsx @@ -0,0 +1,64 @@ +import { Component, Show } from "solid-js" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { popularProviders, useProviders } from "@/hooks/use-providers" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { Tag } from "@opencode-ai/ui/tag" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { IconName } from "@opencode-ai/ui/icons/provider" +import { DialogConnectProvider } from "./dialog-connect-provider" +import { useLanguage } from "@/context/language" + +export const DialogSelectProvider: Component = () => { + const dialog = useDialog() + const providers = useProviders() + const language = useLanguage() + + const popularGroup = () => language.t("dialog.provider.group.popular") + const otherGroup = () => language.t("dialog.provider.group.other") + + return ( + + x?.id} + items={() => { + language.locale() + return providers.all() + }} + filterKeys={["id", "name"]} + groupBy={(x) => (popularProviders.includes(x.id) ? popularGroup() : otherGroup())} + sortBy={(a, b) => { + if (popularProviders.includes(a.id) && popularProviders.includes(b.id)) + return popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id) + return a.name.localeCompare(b.name) + }} + sortGroupsBy={(a, b) => { + const popular = popularGroup() + if (a.category === popular && b.category !== popular) return -1 + if (b.category === popular && a.category !== popular) return 1 + return 0 + }} + onSelect={(x) => { + if (!x) return + dialog.show(() => ) + }} + > + {(i) => ( +
+ + {i.name} + + {language.t("dialog.provider.tag.recommended")} + + +
{language.t("dialog.provider.anthropic.note")}
+
+
+ )} +
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx new file mode 100644 index 00000000000..4466fdde16a --- /dev/null +++ b/packages/app/src/components/dialog-select-server.tsx @@ -0,0 +1,249 @@ +import { createResource, createEffect, createMemo, onCleanup, Show } from "solid-js" +import { createStore, reconcile } from "solid-js/store" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { TextField } from "@opencode-ai/ui/text-field" +import { Button } from "@opencode-ai/ui/button" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { normalizeServerUrl, serverDisplayName, useServer } from "@/context/server" +import { usePlatform } from "@/context/platform" +import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" +import { useNavigate } from "@solidjs/router" +import { useLanguage } from "@/context/language" + +type ServerStatus = { healthy: boolean; version?: string } + +async function checkHealth(url: string, fetch?: typeof globalThis.fetch): Promise { + const sdk = createOpencodeClient({ + baseUrl: url, + fetch, + signal: AbortSignal.timeout(3000), + }) + return sdk.global + .health() + .then((x) => ({ healthy: x.data?.healthy === true, version: x.data?.version })) + .catch(() => ({ healthy: false })) +} + +export function DialogSelectServer() { + const navigate = useNavigate() + const dialog = useDialog() + const server = useServer() + const platform = usePlatform() + const language = useLanguage() + const [store, setStore] = createStore({ + url: "", + adding: false, + error: "", + status: {} as Record, + }) + const [defaultUrl, defaultUrlActions] = createResource(() => platform.getDefaultServerUrl?.()) + const isDesktop = platform.platform === "desktop" + + const items = createMemo(() => { + const current = server.url + const list = server.list + if (!current) return list + if (!list.includes(current)) return [current, ...list] + return [current, ...list.filter((x) => x !== current)] + }) + + const current = createMemo(() => items().find((x) => x === server.url) ?? items()[0]) + + const sortedItems = createMemo(() => { + const list = items() + if (!list.length) return list + const active = current() + const order = new Map(list.map((url, index) => [url, index] as const)) + const rank = (value?: ServerStatus) => { + if (value?.healthy === true) return 0 + if (value?.healthy === false) return 2 + return 1 + } + return list.slice().sort((a, b) => { + if (a === active) return -1 + if (b === active) return 1 + const diff = rank(store.status[a]) - rank(store.status[b]) + if (diff !== 0) return diff + return (order.get(a) ?? 0) - (order.get(b) ?? 0) + }) + }) + + async function refreshHealth() { + const results: Record = {} + await Promise.all( + items().map(async (url) => { + results[url] = await checkHealth(url, platform.fetch) + }), + ) + setStore("status", reconcile(results)) + } + + createEffect(() => { + items() + refreshHealth() + const interval = setInterval(refreshHealth, 10_000) + onCleanup(() => clearInterval(interval)) + }) + + function select(value: string, persist?: boolean) { + if (!persist && store.status[value]?.healthy === false) return + dialog.close() + if (persist) { + server.add(value) + navigate("/") + return + } + server.setActive(value) + navigate("/") + } + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + const value = normalizeServerUrl(store.url) + if (!value) return + + setStore("adding", true) + setStore("error", "") + + const result = await checkHealth(value, platform.fetch) + setStore("adding", false) + + if (!result.healthy) { + setStore("error", language.t("dialog.server.add.error")) + return + } + + setStore("url", "") + select(value, true) + } + + async function handleRemove(url: string) { + server.remove(url) + } + + return ( + +
+ x} + current={current()} + onSelect={(x) => { + if (x) select(x) + }} + > + {(i) => ( +
+
+
+ {serverDisplayName(i)} + {store.status[i]?.version} +
+ + { + e.stopPropagation() + handleRemove(i) + }} + /> + +
+ )} + + +
+
+

{language.t("dialog.server.add.title")}

+
+
+
+
+ { + setStore("url", v) + setStore("error", "") + }} + validationState={store.error ? "invalid" : "valid"} + error={store.error} + /> +
+ +
+
+
+ + +
+
+

{language.t("dialog.server.default.title")}

+

{language.t("dialog.server.default.description")}

+
+
+ {language.t("dialog.server.default.none")} + } + > + + + } + > +
+ {serverDisplayName(defaultUrl()!)} +
+ + +
+
+
+
+
+ ) +} diff --git a/packages/app/src/components/dialog-settings.tsx b/packages/app/src/components/dialog-settings.tsx new file mode 100644 index 00000000000..dbbc8fa7adc --- /dev/null +++ b/packages/app/src/components/dialog-settings.tsx @@ -0,0 +1,112 @@ +import { Component } from "solid-js" +import { Dialog } from "@opencode-ai/ui/dialog" +import { Tabs } from "@opencode-ai/ui/tabs" +import { Icon } from "@opencode-ai/ui/icon" +import { useLanguage } from "@/context/language" +import { usePlatform } from "@/context/platform" +import { SettingsGeneral } from "./settings-general" +import { SettingsKeybinds } from "./settings-keybinds" +import { SettingsPermissions } from "./settings-permissions" +import { SettingsProviders } from "./settings-providers" +import { SettingsModels } from "./settings-models" +import { SettingsAgents } from "./settings-agents" +import { SettingsCommands } from "./settings-commands" +import { SettingsMcp } from "./settings-mcp" + +export const DialogSettings: Component = () => { + const language = useLanguage() + const platform = usePlatform() + + return ( + + + +
+
+ {language.t("settings.section.desktop")} +
+ + + {language.t("settings.tab.general")} + + + + {language.t("settings.tab.shortcuts")} + +
+
+
+ OpenCode Desktop + v{platform.version} +
+
+ {/* Server */} + {/* */} + {/* */} + {/* Permissions */} + {/* */} + {/* */} + {/* */} + {/* Providers */} + {/* */} + {/* */} + {/* */} + {/* Models */} + {/* */} + {/* */} + {/* */} + {/* Agents */} + {/* */} + {/* */} + {/* */} + {/* Commands */} + {/* */} + {/* */} + {/* */} + {/* MCP */} + {/* */} +
+ + + + + + + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} +
+
+ ) +} diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx new file mode 100644 index 00000000000..3439d366cee --- /dev/null +++ b/packages/app/src/components/file-tree.tsx @@ -0,0 +1,112 @@ +import { useLocal, type LocalFile } from "@/context/local" +import { Collapsible } from "@opencode-ai/ui/collapsible" +import { FileIcon } from "@opencode-ai/ui/file-icon" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { For, Match, Switch, type ComponentProps, type ParentProps } from "solid-js" +import { Dynamic } from "solid-js/web" + +export default function FileTree(props: { + path: string + class?: string + nodeClass?: string + level?: number + onFileClick?: (file: LocalFile) => void +}) { + const local = useLocal() + const level = props.level ?? 0 + + const Node = (p: ParentProps & ComponentProps<"div"> & { node: LocalFile; as?: "div" | "button" }) => ( + { + const evt = e as globalThis.DragEvent + evt.dataTransfer!.effectAllowed = "copy" + evt.dataTransfer!.setData("text/plain", `file:${p.node.path}`) + + // Create custom drag image without margins + const dragImage = document.createElement("div") + dragImage.className = + "flex items-center gap-x-2 px-2 py-1 bg-background-element rounded-md border border-border-1" + dragImage.style.position = "absolute" + dragImage.style.top = "-1000px" + + // Copy only the icon and text content without padding + const icon = e.currentTarget.querySelector("svg") + const text = e.currentTarget.querySelector("span") + if (icon && text) { + dragImage.innerHTML = icon.outerHTML + text.outerHTML + } + + document.body.appendChild(dragImage) + evt.dataTransfer!.setDragImage(dragImage, 0, 12) + setTimeout(() => document.body.removeChild(dragImage), 0) + }} + {...p} + > + {p.children} + + {p.node.name} + + {/* */} + {/* */} + {/* */} + + ) + + return ( +
+ + {(node) => ( + + + + (open ? local.file.expand(node.path) : local.file.collapse(node.path))} + > + + + + + + + + + + + + + props.onFileClick?.(node)}> +
+ + + + + + )} + +
+ ) +} diff --git a/packages/app/src/components/link.tsx b/packages/app/src/components/link.tsx new file mode 100644 index 00000000000..e13c3133048 --- /dev/null +++ b/packages/app/src/components/link.tsx @@ -0,0 +1,17 @@ +import { ComponentProps, splitProps } from "solid-js" +import { usePlatform } from "@/context/platform" + +export interface LinkProps extends ComponentProps<"button"> { + href: string +} + +export function Link(props: LinkProps) { + const platform = usePlatform() + const [local, rest] = splitProps(props, ["href", "children"]) + + return ( + + ) +} diff --git a/packages/app/src/components/model-tooltip.tsx b/packages/app/src/components/model-tooltip.tsx new file mode 100644 index 00000000000..53164dae85e --- /dev/null +++ b/packages/app/src/components/model-tooltip.tsx @@ -0,0 +1,91 @@ +import { Show, type Component } from "solid-js" +import { useLanguage } from "@/context/language" + +type InputKey = "text" | "image" | "audio" | "video" | "pdf" +type InputMap = Record + +type ModelInfo = { + id: string + name: string + provider: { + name: string + } + capabilities?: { + reasoning: boolean + input: InputMap + } + modalities?: { + input: Array + } + reasoning?: boolean + limit: { + context: number + } +} + +export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free?: boolean }> = (props) => { + const language = useLanguage() + const sourceName = (model: ModelInfo) => { + const value = `${model.id} ${model.name}`.toLowerCase() + + if (/claude|anthropic/.test(value)) return language.t("model.provider.anthropic") + if (/gpt|o[1-4]|codex|openai/.test(value)) return language.t("model.provider.openai") + if (/gemini|palm|bard|google/.test(value)) return language.t("model.provider.google") + if (/grok|xai/.test(value)) return language.t("model.provider.xai") + if (/llama|meta/.test(value)) return language.t("model.provider.meta") + + return model.provider.name + } + const inputLabel = (value: string) => { + if (value === "text") return language.t("model.input.text") + if (value === "image") return language.t("model.input.image") + if (value === "audio") return language.t("model.input.audio") + if (value === "video") return language.t("model.input.video") + if (value === "pdf") return language.t("model.input.pdf") + return value + } + const title = () => { + const tags: Array = [] + if (props.latest) tags.push(language.t("model.tag.latest")) + if (props.free) tags.push(language.t("model.tag.free")) + const suffix = tags.length ? ` (${tags.join(", ")})` : "" + return `${sourceName(props.model)} ${props.model.name}${suffix}` + } + const inputs = () => { + if (props.model.capabilities) { + const input = props.model.capabilities.input + const order: Array = ["text", "image", "audio", "video", "pdf"] + const entries = order.filter((key) => input[key]).map((key) => inputLabel(key)) + return entries.length ? entries.join(", ") : undefined + } + const raw = props.model.modalities?.input + if (!raw) return + const entries = raw.map((value) => inputLabel(value)) + return entries.length ? entries.join(", ") : undefined + } + const reasoning = () => { + if (props.model.capabilities) + return props.model.capabilities.reasoning + ? language.t("model.tooltip.reasoning.allowed") + : language.t("model.tooltip.reasoning.none") + return props.model.reasoning + ? language.t("model.tooltip.reasoning.allowed") + : language.t("model.tooltip.reasoning.none") + } + const context = () => language.t("model.tooltip.context", { limit: props.model.limit.context.toLocaleString() }) + + return ( +
+
{title()}
+ + {(value) => ( +
+ {language.t("model.tooltip.allows", { inputs: value() })} +
+ )} +
+
{reasoning()}
+
{context()}
+
+ ) +} diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx new file mode 100644 index 00000000000..7670f57656a --- /dev/null +++ b/packages/app/src/components/prompt-input.tsx @@ -0,0 +1,1883 @@ +import { useFilteredList } from "@opencode-ai/ui/hooks" +import { + createEffect, + on, + Component, + Show, + For, + onMount, + onCleanup, + Switch, + Match, + createMemo, + createSignal, +} from "solid-js" +import { createStore, produce } from "solid-js/store" +import { createFocusSignal } from "@solid-primitives/active-element" +import { useLocal } from "@/context/local" +import { useFile, type FileSelection } from "@/context/file" +import { + ContentPart, + DEFAULT_PROMPT, + isPromptEqual, + Prompt, + usePrompt, + ImageAttachmentPart, + AgentPart, + FileAttachmentPart, +} from "@/context/prompt" +import { useLayout } from "@/context/layout" +import { useSDK } from "@/context/sdk" +import { useNavigate, useParams } from "@solidjs/router" +import { useSync } from "@/context/sync" +import { FileIcon } from "@opencode-ai/ui/file-icon" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import type { IconName } from "@opencode-ai/ui/icons/provider" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Select } from "@opencode-ai/ui/select" +import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { ImagePreview } from "@opencode-ai/ui/image-preview" +import { ModelSelectorPopover } from "@/components/dialog-select-model" +import { DialogSelectModelUnpaid } from "@/components/dialog-select-model-unpaid" +import { useProviders } from "@/hooks/use-providers" +import { useCommand } from "@/context/command" +import { Persist, persisted } from "@/utils/persist" +import { Identifier } from "@/utils/id" +import { SessionContextUsage } from "@/components/session-context-usage" +import { usePermission } from "@/context/permission" +import { useLanguage } from "@/context/language" +import { useGlobalSync } from "@/context/global-sync" +import { usePlatform } from "@/context/platform" +import { createOpencodeClient, type Message, type Part } from "@opencode-ai/sdk/v2/client" +import { Binary } from "@opencode-ai/util/binary" +import { showToast } from "@opencode-ai/ui/toast" +import { base64Encode } from "@opencode-ai/util/encode" + +const ACCEPTED_IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"] +const ACCEPTED_FILE_TYPES = [...ACCEPTED_IMAGE_TYPES, "application/pdf"] + +interface PromptInputProps { + class?: string + ref?: (el: HTMLDivElement) => void + newSessionWorktree?: string + onNewSessionWorktreeReset?: () => void + onSubmit?: () => void +} + +const EXAMPLES = [ + "prompt.example.1", + "prompt.example.2", + "prompt.example.3", + "prompt.example.4", + "prompt.example.5", + "prompt.example.6", + "prompt.example.7", + "prompt.example.8", + "prompt.example.9", + "prompt.example.10", + "prompt.example.11", + "prompt.example.12", + "prompt.example.13", + "prompt.example.14", + "prompt.example.15", + "prompt.example.16", + "prompt.example.17", + "prompt.example.18", + "prompt.example.19", + "prompt.example.20", + "prompt.example.21", + "prompt.example.22", + "prompt.example.23", + "prompt.example.24", + "prompt.example.25", +] as const + +interface SlashCommand { + id: string + trigger: string + title: string + description?: string + keybind?: string + type: "builtin" | "custom" +} + +export const PromptInput: Component = (props) => { + const navigate = useNavigate() + const sdk = useSDK() + const sync = useSync() + const globalSync = useGlobalSync() + const platform = usePlatform() + const local = useLocal() + const files = useFile() + const prompt = usePrompt() + const layout = useLayout() + const params = useParams() + const dialog = useDialog() + const providers = useProviders() + const command = useCommand() + const permission = usePermission() + const language = useLanguage() + let editorRef!: HTMLDivElement + let fileInputRef!: HTMLInputElement + let scrollRef!: HTMLDivElement + let slashPopoverRef!: HTMLDivElement + + const scrollCursorIntoView = () => { + const container = scrollRef + const selection = window.getSelection() + if (!container || !selection || selection.rangeCount === 0) return + + const range = selection.getRangeAt(0) + if (!editorRef.contains(range.startContainer)) return + + const rect = range.getBoundingClientRect() + if (!rect.height) return + + const containerRect = container.getBoundingClientRect() + const top = rect.top - containerRect.top + container.scrollTop + const bottom = rect.bottom - containerRect.top + container.scrollTop + const padding = 12 + + if (top < container.scrollTop + padding) { + container.scrollTop = Math.max(0, top - padding) + return + } + + if (bottom > container.scrollTop + container.clientHeight - padding) { + container.scrollTop = bottom - container.clientHeight + padding + } + } + + const queueScroll = () => { + requestAnimationFrame(scrollCursorIntoView) + } + + const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) + const tabs = createMemo(() => layout.tabs(sessionKey())) + const activeFile = createMemo(() => { + const tab = tabs().active() + if (!tab) return + return files.pathFromTab(tab) + }) + const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) + const status = createMemo( + () => + sync.data.session_status[params.id ?? ""] ?? { + type: "idle", + }, + ) + const working = createMemo(() => status()?.type !== "idle") + const imageAttachments = createMemo( + () => prompt.current().filter((part) => part.type === "image") as ImageAttachmentPart[], + ) + + const [store, setStore] = createStore<{ + popover: "at" | "slash" | null + historyIndex: number + savedPrompt: Prompt | null + placeholder: number + dragging: boolean + mode: "normal" | "shell" + applyingHistory: boolean + }>({ + popover: null, + historyIndex: -1, + savedPrompt: null, + placeholder: Math.floor(Math.random() * EXAMPLES.length), + dragging: false, + mode: "normal", + applyingHistory: false, + }) + + const MAX_HISTORY = 100 + const [history, setHistory] = persisted( + Persist.global("prompt-history", ["prompt-history.v1"]), + createStore<{ + entries: Prompt[] + }>({ + entries: [], + }), + ) + const [shellHistory, setShellHistory] = persisted( + Persist.global("prompt-history-shell", ["prompt-history-shell.v1"]), + createStore<{ + entries: Prompt[] + }>({ + entries: [], + }), + ) + + const clonePromptParts = (prompt: Prompt): Prompt => + prompt.map((part) => { + if (part.type === "text") return { ...part } + if (part.type === "image") return { ...part } + if (part.type === "agent") return { ...part } + return { + ...part, + selection: part.selection ? { ...part.selection } : undefined, + } + }) + + const promptLength = (prompt: Prompt) => + prompt.reduce((len, part) => len + ("content" in part ? part.content.length : 0), 0) + + const applyHistoryPrompt = (p: Prompt, position: "start" | "end") => { + const length = position === "start" ? 0 : promptLength(p) + setStore("applyingHistory", true) + prompt.set(p, length) + requestAnimationFrame(() => { + editorRef.focus() + setCursorPosition(editorRef, length) + setStore("applyingHistory", false) + queueScroll() + }) + } + + const getCaretState = () => { + const selection = window.getSelection() + const textLength = promptLength(prompt.current()) + if (!selection || selection.rangeCount === 0) { + return { collapsed: false, cursorPosition: 0, textLength } + } + const anchorNode = selection.anchorNode + if (!anchorNode || !editorRef.contains(anchorNode)) { + return { collapsed: false, cursorPosition: 0, textLength } + } + return { + collapsed: selection.isCollapsed, + cursorPosition: getCursorPosition(editorRef), + textLength, + } + } + + const isFocused = createFocusSignal(() => editorRef) + + createEffect(() => { + params.id + if (params.id) return + const interval = setInterval(() => { + setStore("placeholder", (prev) => (prev + 1) % EXAMPLES.length) + }, 6500) + onCleanup(() => clearInterval(interval)) + }) + + const [composing, setComposing] = createSignal(false) + const isImeComposing = (event: KeyboardEvent) => event.isComposing || composing() || event.keyCode === 229 + + const addImageAttachment = async (file: File) => { + if (!ACCEPTED_FILE_TYPES.includes(file.type)) return + + const reader = new FileReader() + reader.onload = () => { + const dataUrl = reader.result as string + const attachment: ImageAttachmentPart = { + type: "image", + id: crypto.randomUUID(), + filename: file.name, + mime: file.type, + dataUrl, + } + const cursorPosition = prompt.cursor() ?? getCursorPosition(editorRef) + prompt.set([...prompt.current(), attachment], cursorPosition) + } + reader.readAsDataURL(file) + } + + const removeImageAttachment = (id: string) => { + const current = prompt.current() + const next = current.filter((part) => part.type !== "image" || part.id !== id) + prompt.set(next, prompt.cursor()) + } + + const handlePaste = async (event: ClipboardEvent) => { + if (!isFocused()) return + const clipboardData = event.clipboardData + if (!clipboardData) return + + event.preventDefault() + event.stopPropagation() + + const items = Array.from(clipboardData.items) + const fileItems = items.filter((item) => item.kind === "file") + const imageItems = fileItems.filter((item) => ACCEPTED_FILE_TYPES.includes(item.type)) + + if (imageItems.length > 0) { + for (const item of imageItems) { + const file = item.getAsFile() + if (file) await addImageAttachment(file) + } + return + } + + if (fileItems.length > 0) { + showToast({ + title: language.t("prompt.toast.pasteUnsupported.title"), + description: language.t("prompt.toast.pasteUnsupported.description"), + }) + return + } + + const plainText = clipboardData.getData("text/plain") ?? "" + if (!plainText) return + addPart({ type: "text", content: plainText, start: 0, end: 0 }) + } + + const handleGlobalDragOver = (event: DragEvent) => { + if (dialog.active) return + + event.preventDefault() + const hasFiles = event.dataTransfer?.types.includes("Files") + if (hasFiles) { + setStore("dragging", true) + } + } + + const handleGlobalDragLeave = (event: DragEvent) => { + if (dialog.active) return + + // relatedTarget is null when leaving the document window + if (!event.relatedTarget) { + setStore("dragging", false) + } + } + + const handleGlobalDrop = async (event: DragEvent) => { + if (dialog.active) return + + event.preventDefault() + setStore("dragging", false) + + const dropped = event.dataTransfer?.files + if (!dropped) return + + for (const file of Array.from(dropped)) { + if (ACCEPTED_FILE_TYPES.includes(file.type)) { + await addImageAttachment(file) + } + } + } + + onMount(() => { + document.addEventListener("dragover", handleGlobalDragOver) + document.addEventListener("dragleave", handleGlobalDragLeave) + document.addEventListener("drop", handleGlobalDrop) + }) + onCleanup(() => { + document.removeEventListener("dragover", handleGlobalDragOver) + document.removeEventListener("dragleave", handleGlobalDragLeave) + document.removeEventListener("drop", handleGlobalDrop) + }) + + createEffect(() => { + if (!isFocused()) setStore("popover", null) + }) + + // Safety: reset composing state on focus change to prevent stuck state + // This handles edge cases where compositionend event may not fire + createEffect(() => { + if (!isFocused()) setComposing(false) + }) + + type AtOption = { type: "agent"; name: string; display: string } | { type: "file"; path: string; display: string } + + const agentList = createMemo(() => + sync.data.agent + .filter((agent) => !agent.hidden && agent.mode !== "primary") + .map((agent): AtOption => ({ type: "agent", name: agent.name, display: agent.name })), + ) + + const handleAtSelect = (option: AtOption | undefined) => { + if (!option) return + if (option.type === "agent") { + addPart({ type: "agent", name: option.name, content: "@" + option.name, start: 0, end: 0 }) + } else { + addPart({ type: "file", path: option.path, content: "@" + option.path, start: 0, end: 0 }) + } + } + + const atKey = (x: AtOption | undefined) => { + if (!x) return "" + return x.type === "agent" ? `agent:${x.name}` : `file:${x.path}` + } + + const { + flat: atFlat, + active: atActive, + setActive: setAtActive, + onInput: atOnInput, + onKeyDown: atOnKeyDown, + } = useFilteredList({ + items: async (query) => { + const agents = agentList() + const paths = await files.searchFilesAndDirectories(query) + const fileOptions: AtOption[] = paths.map((path) => ({ type: "file", path, display: path })) + return [...agents, ...fileOptions] + }, + key: atKey, + filterKeys: ["display"], + onSelect: handleAtSelect, + }) + + const slashCommands = createMemo(() => { + const builtin = command.options + .filter((opt) => !opt.disabled && !opt.id.startsWith("suggested.") && opt.slash) + .map((opt) => ({ + id: opt.id, + trigger: opt.slash!, + title: opt.title, + description: opt.description, + keybind: opt.keybind, + type: "builtin" as const, + })) + + const custom = sync.data.command.map((cmd) => ({ + id: `custom.${cmd.name}`, + trigger: cmd.name, + title: cmd.name, + description: cmd.description, + type: "custom" as const, + })) + + return [...custom, ...builtin] + }) + + const handleSlashSelect = (cmd: SlashCommand | undefined) => { + if (!cmd) return + setStore("popover", null) + + if (cmd.type === "custom") { + const text = `/${cmd.trigger} ` + editorRef.innerHTML = "" + editorRef.textContent = text + prompt.set([{ type: "text", content: text, start: 0, end: text.length }], text.length) + requestAnimationFrame(() => { + editorRef.focus() + const range = document.createRange() + const sel = window.getSelection() + range.selectNodeContents(editorRef) + range.collapse(false) + sel?.removeAllRanges() + sel?.addRange(range) + }) + return + } + + editorRef.innerHTML = "" + prompt.set([{ type: "text", content: "", start: 0, end: 0 }], 0) + command.trigger(cmd.id, "slash") + } + + const { + flat: slashFlat, + active: slashActive, + setActive: setSlashActive, + onInput: slashOnInput, + onKeyDown: slashOnKeyDown, + refetch: slashRefetch, + } = useFilteredList({ + items: slashCommands, + key: (x) => x?.id, + filterKeys: ["trigger", "title", "description"], + onSelect: handleSlashSelect, + }) + + const createPill = (part: FileAttachmentPart | AgentPart) => { + const pill = document.createElement("span") + pill.textContent = part.content + pill.setAttribute("data-type", part.type) + if (part.type === "file") pill.setAttribute("data-path", part.path) + if (part.type === "agent") pill.setAttribute("data-name", part.name) + pill.setAttribute("contenteditable", "false") + pill.style.userSelect = "text" + pill.style.cursor = "default" + return pill + } + + const isNormalizedEditor = () => + Array.from(editorRef.childNodes).every((node) => { + if (node.nodeType === Node.TEXT_NODE) { + const text = node.textContent ?? "" + if (!text.includes("\u200B")) return true + if (text !== "\u200B") return false + + const prev = node.previousSibling + const next = node.nextSibling + const prevIsBr = prev?.nodeType === Node.ELEMENT_NODE && (prev as HTMLElement).tagName === "BR" + const nextIsBr = next?.nodeType === Node.ELEMENT_NODE && (next as HTMLElement).tagName === "BR" + if (!prevIsBr && !nextIsBr) return false + if (nextIsBr && !prevIsBr && prev) return false + return true + } + if (node.nodeType !== Node.ELEMENT_NODE) return false + const el = node as HTMLElement + if (el.dataset.type === "file") return true + if (el.dataset.type === "agent") return true + return el.tagName === "BR" + }) + + const renderEditor = (parts: Prompt) => { + editorRef.innerHTML = "" + for (const part of parts) { + if (part.type === "text") { + editorRef.appendChild(createTextFragment(part.content)) + continue + } + if (part.type === "file" || part.type === "agent") { + editorRef.appendChild(createPill(part)) + } + } + } + + createEffect( + on( + () => sync.data.command, + () => slashRefetch(), + { defer: true }, + ), + ) + + // Auto-scroll active command into view when navigating with keyboard + createEffect(() => { + const activeId = slashActive() + if (!activeId || !slashPopoverRef) return + + requestAnimationFrame(() => { + const element = slashPopoverRef.querySelector(`[data-slash-id="${activeId}"]`) + element?.scrollIntoView({ block: "nearest", behavior: "smooth" }) + }) + }) + + const selectPopoverActive = () => { + if (store.popover === "at") { + const items = atFlat() + if (items.length === 0) return + const active = atActive() + const item = items.find((entry) => atKey(entry) === active) ?? items[0] + handleAtSelect(item) + return + } + + if (store.popover === "slash") { + const items = slashFlat() + if (items.length === 0) return + const active = slashActive() + const item = items.find((entry) => entry.id === active) ?? items[0] + handleSlashSelect(item) + } + } + + createEffect( + on( + () => prompt.current(), + (currentParts) => { + const inputParts = currentParts.filter((part) => part.type !== "image") as Prompt + const domParts = parseFromDOM() + if (isNormalizedEditor() && isPromptEqual(inputParts, domParts)) return + + const selection = window.getSelection() + let cursorPosition: number | null = null + if (selection && selection.rangeCount > 0 && editorRef.contains(selection.anchorNode)) { + cursorPosition = getCursorPosition(editorRef) + } + + renderEditor(inputParts) + + if (cursorPosition !== null) { + setCursorPosition(editorRef, cursorPosition) + } + }, + ), + ) + + const parseFromDOM = (): Prompt => { + const parts: Prompt = [] + let position = 0 + let buffer = "" + + const flushText = () => { + const content = buffer.replace(/\r\n?/g, "\n").replace(/\u200B/g, "") + buffer = "" + if (!content) return + parts.push({ type: "text", content, start: position, end: position + content.length }) + position += content.length + } + + const pushFile = (file: HTMLElement) => { + const content = file.textContent ?? "" + parts.push({ + type: "file", + path: file.dataset.path!, + content, + start: position, + end: position + content.length, + }) + position += content.length + } + + const pushAgent = (agent: HTMLElement) => { + const content = agent.textContent ?? "" + parts.push({ + type: "agent", + name: agent.dataset.name!, + content, + start: position, + end: position + content.length, + }) + position += content.length + } + + const visit = (node: Node) => { + if (node.nodeType === Node.TEXT_NODE) { + buffer += node.textContent ?? "" + return + } + if (node.nodeType !== Node.ELEMENT_NODE) return + + const el = node as HTMLElement + if (el.dataset.type === "file") { + flushText() + pushFile(el) + return + } + if (el.dataset.type === "agent") { + flushText() + pushAgent(el) + return + } + if (el.tagName === "BR") { + buffer += "\n" + return + } + + for (const child of Array.from(el.childNodes)) { + visit(child) + } + } + + const children = Array.from(editorRef.childNodes) + children.forEach((child, index) => { + const isBlock = child.nodeType === Node.ELEMENT_NODE && ["DIV", "P"].includes((child as HTMLElement).tagName) + visit(child) + if (isBlock && index < children.length - 1) { + buffer += "\n" + } + }) + + flushText() + + if (parts.length === 0) parts.push(...DEFAULT_PROMPT) + return parts + } + + const handleInput = () => { + const rawParts = parseFromDOM() + const images = imageAttachments() + const cursorPosition = getCursorPosition(editorRef) + const rawText = rawParts.map((p) => ("content" in p ? p.content : "")).join("") + const trimmed = rawText.replace(/\u200B/g, "").trim() + const hasNonText = rawParts.some((part) => part.type !== "text") + const shouldReset = trimmed.length === 0 && !hasNonText && images.length === 0 + + if (shouldReset) { + setStore("popover", null) + if (store.historyIndex >= 0 && !store.applyingHistory) { + setStore("historyIndex", -1) + setStore("savedPrompt", null) + } + if (prompt.dirty()) { + prompt.set(DEFAULT_PROMPT, 0) + } + queueScroll() + return + } + + const shellMode = store.mode === "shell" + + if (!shellMode) { + const atMatch = rawText.substring(0, cursorPosition).match(/@(\S*)$/) + const slashMatch = rawText.match(/^\/(\S*)$/) + + if (atMatch) { + atOnInput(atMatch[1]) + setStore("popover", "at") + } else if (slashMatch) { + slashOnInput(slashMatch[1]) + setStore("popover", "slash") + } else { + setStore("popover", null) + } + } else { + setStore("popover", null) + } + + if (store.historyIndex >= 0 && !store.applyingHistory) { + setStore("historyIndex", -1) + setStore("savedPrompt", null) + } + + prompt.set([...rawParts, ...images], cursorPosition) + queueScroll() + } + + const setRangeEdge = (range: Range, edge: "start" | "end", offset: number) => { + let remaining = offset + const nodes = Array.from(editorRef.childNodes) + + for (const node of nodes) { + const length = getNodeLength(node) + const isText = node.nodeType === Node.TEXT_NODE + const isPill = + node.nodeType === Node.ELEMENT_NODE && + ((node as HTMLElement).dataset.type === "file" || (node as HTMLElement).dataset.type === "agent") + const isBreak = node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === "BR" + + if (isText && remaining <= length) { + if (edge === "start") range.setStart(node, remaining) + if (edge === "end") range.setEnd(node, remaining) + return + } + + if ((isPill || isBreak) && remaining <= length) { + if (edge === "start" && remaining === 0) range.setStartBefore(node) + if (edge === "start" && remaining > 0) range.setStartAfter(node) + if (edge === "end" && remaining === 0) range.setEndBefore(node) + if (edge === "end" && remaining > 0) range.setEndAfter(node) + return + } + + remaining -= length + } + } + + const addPart = (part: ContentPart) => { + const selection = window.getSelection() + if (!selection || selection.rangeCount === 0) return + + const cursorPosition = getCursorPosition(editorRef) + const currentPrompt = prompt.current() + const rawText = currentPrompt.map((p) => ("content" in p ? p.content : "")).join("") + const textBeforeCursor = rawText.substring(0, cursorPosition) + const atMatch = textBeforeCursor.match(/@(\S*)$/) + + if (part.type === "file" || part.type === "agent") { + const pill = createPill(part) + const gap = document.createTextNode(" ") + const range = selection.getRangeAt(0) + + if (atMatch) { + const start = atMatch.index ?? cursorPosition - atMatch[0].length + setRangeEdge(range, "start", start) + setRangeEdge(range, "end", cursorPosition) + } + + range.deleteContents() + range.insertNode(gap) + range.insertNode(pill) + range.setStartAfter(gap) + range.collapse(true) + selection.removeAllRanges() + selection.addRange(range) + } else if (part.type === "text") { + const range = selection.getRangeAt(0) + const fragment = createTextFragment(part.content) + const last = fragment.lastChild + range.deleteContents() + range.insertNode(fragment) + if (last) { + if (last.nodeType === Node.TEXT_NODE) { + const text = last.textContent ?? "" + if (text === "\u200B") { + range.setStart(last, 0) + } + if (text !== "\u200B") { + range.setStart(last, text.length) + } + } + if (last.nodeType !== Node.TEXT_NODE) { + range.setStartAfter(last) + } + } + range.collapse(true) + selection.removeAllRanges() + selection.addRange(range) + } + + handleInput() + setStore("popover", null) + } + + const abort = () => + sdk.client.session + .abort({ + sessionID: params.id!, + }) + .catch(() => {}) + + const addToHistory = (prompt: Prompt, mode: "normal" | "shell") => { + const text = prompt + .map((p) => ("content" in p ? p.content : "")) + .join("") + .trim() + const hasImages = prompt.some((part) => part.type === "image") + if (!text && !hasImages) return + + const entry = clonePromptParts(prompt) + const currentHistory = mode === "shell" ? shellHistory : history + const setCurrentHistory = mode === "shell" ? setShellHistory : setHistory + const lastEntry = currentHistory.entries[0] + if (lastEntry && isPromptEqual(lastEntry, entry)) return + + setCurrentHistory("entries", (entries) => [entry, ...entries].slice(0, MAX_HISTORY)) + } + + const navigateHistory = (direction: "up" | "down") => { + const entries = store.mode === "shell" ? shellHistory.entries : history.entries + const current = store.historyIndex + + if (direction === "up") { + if (entries.length === 0) return false + if (current === -1) { + setStore("savedPrompt", clonePromptParts(prompt.current())) + setStore("historyIndex", 0) + applyHistoryPrompt(entries[0], "start") + return true + } + if (current < entries.length - 1) { + const next = current + 1 + setStore("historyIndex", next) + applyHistoryPrompt(entries[next], "start") + return true + } + return false + } + + if (current > 0) { + const next = current - 1 + setStore("historyIndex", next) + applyHistoryPrompt(entries[next], "end") + return true + } + if (current === 0) { + setStore("historyIndex", -1) + const saved = store.savedPrompt + if (saved) { + applyHistoryPrompt(saved, "end") + setStore("savedPrompt", null) + return true + } + applyHistoryPrompt(DEFAULT_PROMPT, "end") + return true + } + + return false + } + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Backspace") { + const selection = window.getSelection() + if (selection && selection.isCollapsed) { + const node = selection.anchorNode + const offset = selection.anchorOffset + if (node && node.nodeType === Node.TEXT_NODE) { + const text = node.textContent ?? "" + if (/^\u200B+$/.test(text) && offset > 0) { + const range = document.createRange() + range.setStart(node, 0) + range.collapse(true) + selection.removeAllRanges() + selection.addRange(range) + } + } + } + } + + if (event.key === "!" && store.mode === "normal") { + const cursorPosition = getCursorPosition(editorRef) + if (cursorPosition === 0) { + setStore("mode", "shell") + setStore("popover", null) + event.preventDefault() + return + } + } + if (store.mode === "shell") { + const { collapsed, cursorPosition, textLength } = getCaretState() + if (event.key === "Escape") { + setStore("mode", "normal") + event.preventDefault() + return + } + if (event.key === "Backspace" && collapsed && cursorPosition === 0 && textLength === 0) { + setStore("mode", "normal") + event.preventDefault() + return + } + } + + // Handle Shift+Enter BEFORE IME check - Shift+Enter is never used for IME input + // and should always insert a newline regardless of composition state + if (event.key === "Enter" && event.shiftKey) { + addPart({ type: "text", content: "\n", start: 0, end: 0 }) + event.preventDefault() + return + } + + if (event.key === "Enter" && isImeComposing(event)) { + return + } + + if (store.popover) { + if (event.key === "Tab") { + selectPopoverActive() + event.preventDefault() + return + } + if (event.key === "ArrowUp" || event.key === "ArrowDown" || event.key === "Enter") { + if (store.popover === "at") { + atOnKeyDown(event) + event.preventDefault() + return + } + if (store.popover === "slash") { + slashOnKeyDown(event) + } + event.preventDefault() + return + } + } + + const ctrl = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey + + if (ctrl && event.code === "KeyG") { + if (store.popover) { + setStore("popover", null) + event.preventDefault() + return + } + if (working()) { + abort() + event.preventDefault() + } + return + } + + if (event.key === "ArrowUp" || event.key === "ArrowDown") { + if (event.altKey || event.ctrlKey || event.metaKey) return + const { collapsed } = getCaretState() + if (!collapsed) return + + const cursorPosition = getCursorPosition(editorRef) + const textLength = promptLength(prompt.current()) + const textContent = prompt + .current() + .map((part) => ("content" in part ? part.content : "")) + .join("") + const isEmpty = textContent.trim() === "" || textLength <= 1 + const hasNewlines = textContent.includes("\n") + const inHistory = store.historyIndex >= 0 + const atStart = cursorPosition <= (isEmpty ? 1 : 0) + const atEnd = cursorPosition >= (isEmpty ? textLength - 1 : textLength) + const allowUp = isEmpty || atStart || (!hasNewlines && !inHistory) || (inHistory && atEnd) + const allowDown = isEmpty || atEnd || (!hasNewlines && !inHistory) || (inHistory && atStart) + + if (event.key === "ArrowUp") { + if (!allowUp) return + if (navigateHistory("up")) { + event.preventDefault() + } + return + } + + if (!allowDown) return + if (navigateHistory("down")) { + event.preventDefault() + } + return + } + + // Note: Shift+Enter is handled earlier, before IME check + if (event.key === "Enter" && !event.shiftKey) { + handleSubmit(event) + } + if (event.key === "Escape") { + if (store.popover) { + setStore("popover", null) + } else if (working()) { + abort() + } + } + } + + const handleSubmit = async (event: Event) => { + event.preventDefault() + + const currentPrompt = prompt.current() + const text = currentPrompt.map((part) => ("content" in part ? part.content : "")).join("") + const images = imageAttachments().slice() + const mode = store.mode + + if (text.trim().length === 0 && images.length === 0) { + if (working()) abort() + return + } + + const currentModel = local.model.current() + const currentAgent = local.agent.current() + if (!currentModel || !currentAgent) { + showToast({ + title: language.t("prompt.toast.modelAgentRequired.title"), + description: language.t("prompt.toast.modelAgentRequired.description"), + }) + return + } + + const errorMessage = (err: unknown) => { + if (err && typeof err === "object" && "data" in err) { + const data = (err as { data?: { message?: string } }).data + if (data?.message) return data.message + } + if (err instanceof Error) return err.message + return language.t("common.requestFailed") + } + + addToHistory(currentPrompt, mode) + setStore("historyIndex", -1) + setStore("savedPrompt", null) + + const projectDirectory = sdk.directory + const isNewSession = !params.id + const worktreeSelection = props.newSessionWorktree ?? "main" + + let sessionDirectory = projectDirectory + let client = sdk.client + + if (isNewSession) { + if (worktreeSelection === "create") { + const createdWorktree = await client.worktree + .create({ directory: projectDirectory }) + .then((x) => x.data) + .catch((err) => { + showToast({ + title: language.t("prompt.toast.worktreeCreateFailed.title"), + description: errorMessage(err), + }) + return undefined + }) + + if (!createdWorktree?.directory) { + showToast({ + title: language.t("prompt.toast.worktreeCreateFailed.title"), + description: language.t("common.requestFailed"), + }) + return + } + sessionDirectory = createdWorktree.directory + } + + if (worktreeSelection !== "main" && worktreeSelection !== "create") { + sessionDirectory = worktreeSelection + } + + if (sessionDirectory !== projectDirectory) { + client = createOpencodeClient({ + baseUrl: sdk.url, + fetch: platform.fetch, + directory: sessionDirectory, + throwOnError: true, + }) + globalSync.child(sessionDirectory) + } + + props.onNewSessionWorktreeReset?.() + } + + let session = info() + if (!session && isNewSession) { + session = await client.session + .create() + .then((x) => x.data ?? undefined) + .catch((err) => { + showToast({ + title: language.t("prompt.toast.sessionCreateFailed.title"), + description: errorMessage(err), + }) + return undefined + }) + if (session) navigate(`/${base64Encode(sessionDirectory)}/session/${session.id}`) + } + if (!session) return + + props.onSubmit?.() + + const model = { + modelID: currentModel.id, + providerID: currentModel.provider.id, + } + const agent = currentAgent.name + const variant = local.model.variant.current() + + const clearInput = () => { + prompt.reset() + setStore("mode", "normal") + setStore("popover", null) + } + + const restoreInput = () => { + prompt.set(currentPrompt, promptLength(currentPrompt)) + setStore("mode", mode) + setStore("popover", null) + requestAnimationFrame(() => { + editorRef.focus() + setCursorPosition(editorRef, promptLength(currentPrompt)) + queueScroll() + }) + } + + if (mode === "shell") { + clearInput() + client.session + .shell({ + sessionID: session.id, + agent, + model, + command: text, + }) + .catch((err) => { + showToast({ + title: language.t("prompt.toast.shellSendFailed.title"), + description: errorMessage(err), + }) + restoreInput() + }) + return + } + + if (text.startsWith("/")) { + const [cmdName, ...args] = text.split(" ") + const commandName = cmdName.slice(1) + const customCommand = sync.data.command.find((c) => c.name === commandName) + if (customCommand) { + clearInput() + client.session + .command({ + sessionID: session.id, + command: commandName, + arguments: args.join(" "), + agent, + model: `${model.providerID}/${model.modelID}`, + variant, + parts: images.map((attachment) => ({ + id: Identifier.ascending("part"), + type: "file" as const, + mime: attachment.mime, + url: attachment.dataUrl, + filename: attachment.filename, + })), + }) + .catch((err) => { + showToast({ + title: language.t("prompt.toast.commandSendFailed.title"), + description: errorMessage(err), + }) + restoreInput() + }) + return + } + } + + const toAbsolutePath = (path: string) => + path.startsWith("/") ? path : (sessionDirectory + "/" + path).replace("//", "/") + + const fileAttachments = currentPrompt.filter((part) => part.type === "file") as FileAttachmentPart[] + const agentAttachments = currentPrompt.filter((part) => part.type === "agent") as AgentPart[] + + const fileAttachmentParts = fileAttachments.map((attachment) => { + const absolute = toAbsolutePath(attachment.path) + const query = attachment.selection + ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` + : "" + return { + id: Identifier.ascending("part"), + type: "file" as const, + mime: "text/plain", + url: `file://${absolute}${query}`, + filename: getFilename(attachment.path), + source: { + type: "file" as const, + text: { + value: attachment.content, + start: attachment.start, + end: attachment.end, + }, + path: absolute, + }, + } + }) + + const agentAttachmentParts = agentAttachments.map((attachment) => ({ + id: Identifier.ascending("part"), + type: "agent" as const, + name: attachment.name, + source: { + value: attachment.content, + start: attachment.start, + end: attachment.end, + }, + })) + + const usedUrls = new Set(fileAttachmentParts.map((part) => part.url)) + + const contextFileParts: Array<{ + id: string + type: "file" + mime: string + url: string + filename?: string + }> = [] + + const addContextFile = (path: string, selection?: FileSelection) => { + const absolute = toAbsolutePath(path) + const query = selection ? `?start=${selection.startLine}&end=${selection.endLine}` : "" + const url = `file://${absolute}${query}` + if (usedUrls.has(url)) return + usedUrls.add(url) + contextFileParts.push({ + id: Identifier.ascending("part"), + type: "file", + mime: "text/plain", + url, + filename: getFilename(path), + }) + } + + const activePath = activeFile() + if (activePath && prompt.context.activeTab()) { + addContextFile(activePath) + } + + for (const item of prompt.context.items()) { + if (item.type !== "file") continue + addContextFile(item.path, item.selection) + } + + const imageAttachmentParts = images.map((attachment) => ({ + id: Identifier.ascending("part"), + type: "file" as const, + mime: attachment.mime, + url: attachment.dataUrl, + filename: attachment.filename, + })) + + const messageID = Identifier.ascending("message") + const textPart = { + id: Identifier.ascending("part"), + type: "text" as const, + text, + } + const requestParts = [ + textPart, + ...fileAttachmentParts, + ...contextFileParts, + ...agentAttachmentParts, + ...imageAttachmentParts, + ] + + const optimisticParts = requestParts.map((part) => ({ + ...part, + sessionID: session.id, + messageID, + })) as unknown as Part[] + + const optimisticMessage: Message = { + id: messageID, + sessionID: session.id, + role: "user", + time: { created: Date.now() }, + agent, + model, + } + + const setSyncStore = sessionDirectory === projectDirectory ? sync.set : globalSync.child(sessionDirectory)[1] + + const addOptimisticMessage = () => { + setSyncStore( + produce((draft) => { + const messages = draft.message[session.id] + if (!messages) { + draft.message[session.id] = [optimisticMessage] + } else { + const result = Binary.search(messages, messageID, (m) => m.id) + messages.splice(result.index, 0, optimisticMessage) + } + draft.part[messageID] = optimisticParts + .filter((p) => !!p?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + }), + ) + } + + const removeOptimisticMessage = () => { + setSyncStore( + produce((draft) => { + const messages = draft.message[session.id] + if (messages) { + const result = Binary.search(messages, messageID, (m) => m.id) + if (result.found) messages.splice(result.index, 1) + } + delete draft.part[messageID] + }), + ) + } + + clearInput() + addOptimisticMessage() + + client.session + .prompt({ + sessionID: session.id, + agent, + model, + messageID, + parts: requestParts, + variant, + }) + .catch((err) => { + showToast({ + title: language.t("prompt.toast.promptSendFailed.title"), + description: errorMessage(err), + }) + removeOptimisticMessage() + restoreInput() + }) + } + + return ( +
+ +
{ + if (store.popover === "slash") slashPopoverRef = el + }} + class="absolute inset-x-0 -top-3 -translate-y-full origin-bottom-left max-h-80 min-h-10 + overflow-auto no-scrollbar flex flex-col p-2 rounded-md + border border-border-base bg-surface-raised-stronger-non-alpha shadow-md" + onMouseDown={(e) => e.preventDefault()} + > + + + 0} + fallback={
{language.t("prompt.popover.emptyResults")}
} + > + + {(item) => ( + + )} + +
+
+ + 0} + fallback={
{language.t("prompt.popover.emptyCommands")}
} + > + + {(cmd) => ( + + )} + +
+
+
+
+
+
+ +
+
+ + {language.t("prompt.dropzone.label")} +
+
+
+ 0 || !!activeFile())}> +
+ + {(path) => ( +
+ +
+ {getDirectory(path())} + {getFilename(path())} + {language.t("prompt.context.active")} +
+ prompt.context.removeActive()} + aria-label={language.t("prompt.context.removeActiveFile")} + /> +
+ )} +
+ + + + + {(item) => ( +
+ +
+ {getDirectory(item.path)} + {getFilename(item.path)} + + {(sel) => ( + + {sel().startLine === sel().endLine + ? `:${sel().startLine}` + : `:${sel().startLine}-${sel().endLine}`} + + )} + +
+ prompt.context.remove(item.key)} + aria-label={language.t("prompt.context.removeFile")} + /> +
+ )} +
+
+
+ 0}> +
+ + {(attachment) => ( +
+ + +
+ } + > + {attachment.filename} + dialog.show(() => ) + } + /> + + +
+ {attachment.filename} +
+
+ )} + +
+ +
(scrollRef = el)}> +
{ + editorRef = el + props.ref?.(el) + }} + role="textbox" + aria-multiline="true" + aria-label={ + store.mode === "shell" + ? language.t("prompt.placeholder.shell") + : language.t("prompt.placeholder.normal", { example: language.t(EXAMPLES[store.placeholder]) }) + } + contenteditable="true" + onInput={handleInput} + onPaste={handlePaste} + onCompositionStart={() => setComposing(true)} + onCompositionEnd={() => setComposing(false)} + onKeyDown={handleKeyDown} + classList={{ + "select-text": true, + "w-full px-5 py-3 pr-12 text-14-regular text-text-strong focus:outline-none whitespace-pre-wrap": true, + "[&_[data-type=file]]:text-syntax-property": true, + "[&_[data-type=agent]]:text-syntax-type": true, + "font-mono!": store.mode === "shell", + }} + /> + +
+ {store.mode === "shell" + ? language.t("prompt.placeholder.shell") + : language.t("prompt.placeholder.normal", { example: language.t(EXAMPLES[store.placeholder]) })} +
+
+
+
+
+ + +
+ + {language.t("prompt.mode.shell")} + {language.t("prompt.mode.shell.exit")} +
+
+ + + { + const file = e.currentTarget.files?.[0] + if (file) addImageAttachment(file) + e.currentTarget.value = "" + }} + /> +
+ + + + + + +
+ + +
+ {language.t("prompt.action.stop")} + {language.t("common.key.esc")} +
+
+ +
+ {language.t("prompt.action.send")} + +
+
+
+ } + > + + +
+
+ +
+ ) +} + +function createTextFragment(content: string): DocumentFragment { + const fragment = document.createDocumentFragment() + const segments = content.split("\n") + segments.forEach((segment, index) => { + if (segment) { + fragment.appendChild(document.createTextNode(segment)) + } else if (segments.length > 1) { + fragment.appendChild(document.createTextNode("\u200B")) + } + if (index < segments.length - 1) { + fragment.appendChild(document.createElement("br")) + } + }) + return fragment +} + +function getNodeLength(node: Node): number { + if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === "BR") return 1 + return (node.textContent ?? "").replace(/\u200B/g, "").length +} + +function getTextLength(node: Node): number { + if (node.nodeType === Node.TEXT_NODE) return (node.textContent ?? "").replace(/\u200B/g, "").length + if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === "BR") return 1 + let length = 0 + for (const child of Array.from(node.childNodes)) { + length += getTextLength(child) + } + return length +} + +function getCursorPosition(parent: HTMLElement): number { + const selection = window.getSelection() + if (!selection || selection.rangeCount === 0) return 0 + const range = selection.getRangeAt(0) + if (!parent.contains(range.startContainer)) return 0 + const preCaretRange = range.cloneRange() + preCaretRange.selectNodeContents(parent) + preCaretRange.setEnd(range.startContainer, range.startOffset) + return getTextLength(preCaretRange.cloneContents()) +} + +function setCursorPosition(parent: HTMLElement, position: number) { + let remaining = position + let node = parent.firstChild + while (node) { + const length = getNodeLength(node) + const isText = node.nodeType === Node.TEXT_NODE + const isPill = + node.nodeType === Node.ELEMENT_NODE && + ((node as HTMLElement).dataset.type === "file" || (node as HTMLElement).dataset.type === "agent") + const isBreak = node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === "BR" + + if (isText && remaining <= length) { + const range = document.createRange() + const selection = window.getSelection() + range.setStart(node, remaining) + range.collapse(true) + selection?.removeAllRanges() + selection?.addRange(range) + return + } + + if ((isPill || isBreak) && remaining <= length) { + const range = document.createRange() + const selection = window.getSelection() + if (remaining === 0) { + range.setStartBefore(node) + } + if (remaining > 0 && isPill) { + range.setStartAfter(node) + } + if (remaining > 0 && isBreak) { + const next = node.nextSibling + if (next && next.nodeType === Node.TEXT_NODE) { + range.setStart(next, 0) + } + if (!next || next.nodeType !== Node.TEXT_NODE) { + range.setStartAfter(node) + } + } + range.collapse(true) + selection?.removeAllRanges() + selection?.addRange(range) + return + } + + remaining -= length + node = node.nextSibling + } + + const fallbackRange = document.createRange() + const fallbackSelection = window.getSelection() + const last = parent.lastChild + if (last && last.nodeType === Node.TEXT_NODE) { + const len = last.textContent ? last.textContent.length : 0 + fallbackRange.setStart(last, len) + } + if (!last || last.nodeType !== Node.TEXT_NODE) { + fallbackRange.selectNodeContents(parent) + } + fallbackRange.collapse(false) + fallbackSelection?.removeAllRanges() + fallbackSelection?.addRange(fallbackRange) +} diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx new file mode 100644 index 00000000000..ee93b3f03c0 --- /dev/null +++ b/packages/app/src/components/session-context-usage.tsx @@ -0,0 +1,113 @@ +import { Match, Show, Switch, createMemo } from "solid-js" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { ProgressCircle } from "@opencode-ai/ui/progress-circle" +import { Button } from "@opencode-ai/ui/button" +import { useParams } from "@solidjs/router" +import { AssistantMessage } from "@opencode-ai/sdk/v2/client" + +import { useLayout } from "@/context/layout" +import { useSync } from "@/context/sync" +import { useLanguage } from "@/context/language" + +interface SessionContextUsageProps { + variant?: "button" | "indicator" +} + +export function SessionContextUsage(props: SessionContextUsageProps) { + const sync = useSync() + const params = useParams() + const layout = useLayout() + const language = useLanguage() + + const variant = createMemo(() => props.variant ?? "button") + const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) + const tabs = createMemo(() => layout.tabs(sessionKey())) + const view = createMemo(() => layout.view(sessionKey())) + const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : [])) + + const cost = createMemo(() => { + const locale = language.locale() + const total = messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0) + return new Intl.NumberFormat(locale, { + style: "currency", + currency: "USD", + }).format(total) + }) + + const context = createMemo(() => { + const locale = language.locale() + const last = messages().findLast((x) => { + if (x.role !== "assistant") return false + const total = x.tokens.input + x.tokens.output + x.tokens.reasoning + x.tokens.cache.read + x.tokens.cache.write + return total > 0 + }) as AssistantMessage + if (!last) return + const total = + last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write + const model = sync.data.provider.all.find((x) => x.id === last.providerID)?.models[last.modelID] + return { + tokens: total.toLocaleString(locale), + percentage: model?.limit.context ? Math.round((total / model.limit.context) * 100) : null, + } + }) + + const openContext = () => { + if (!params.id) return + view().reviewPanel.open() + tabs().open("context") + tabs().setActive("context") + } + + const circle = () => ( +
+ +
+ ) + + const tooltipValue = () => ( +
+ + {(ctx) => ( + <> +
+ {ctx().tokens} + {language.t("context.usage.tokens")} +
+
+ {ctx().percentage ?? 0}% + {language.t("context.usage.usage")} +
+ + )} +
+
+ {cost()} + {language.t("context.usage.cost")} +
+ +
{language.t("context.usage.clickToView")}
+
+
+ ) + + return ( + + + + {circle()} + + + + + + + ) +} diff --git a/packages/app/src/components/session-lsp-indicator.tsx b/packages/app/src/components/session-lsp-indicator.tsx new file mode 100644 index 00000000000..dab92920ec4 --- /dev/null +++ b/packages/app/src/components/session-lsp-indicator.tsx @@ -0,0 +1,42 @@ +import { createMemo, Show } from "solid-js" +import { useSync } from "@/context/sync" +import { useLanguage } from "@/context/language" +import { Tooltip } from "@opencode-ai/ui/tooltip" + +export function SessionLspIndicator() { + const sync = useSync() + const language = useLanguage() + + const lspStats = createMemo(() => { + const lsp = sync.data.lsp ?? [] + const connected = lsp.filter((s) => s.status === "connected").length + const hasError = lsp.some((s) => s.status === "error") + const total = lsp.length + return { connected, hasError, total } + }) + + const tooltipContent = createMemo(() => { + const lsp = sync.data.lsp ?? [] + if (lsp.length === 0) return language.t("lsp.tooltip.none") + return lsp.map((s) => s.name).join(", ") + }) + + return ( + 0}> + +
+
0, + }} + /> + + {language.t("lsp.label.connected", { count: lspStats().connected })} + +
+ + + ) +} diff --git a/packages/app/src/components/session-mcp-indicator.tsx b/packages/app/src/components/session-mcp-indicator.tsx new file mode 100644 index 00000000000..489223b9bf5 --- /dev/null +++ b/packages/app/src/components/session-mcp-indicator.tsx @@ -0,0 +1,34 @@ +import { createMemo, Show } from "solid-js" +import { Button } from "@opencode-ai/ui/button" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useSync } from "@/context/sync" +import { DialogSelectMcp } from "@/components/dialog-select-mcp" + +export function SessionMcpIndicator() { + const sync = useSync() + const dialog = useDialog() + + const mcpStats = createMemo(() => { + const mcp = sync.data.mcp ?? {} + const entries = Object.entries(mcp) + const enabled = entries.filter(([, status]) => status.status === "connected").length + const failed = entries.some(([, status]) => status.status === "failed") + const total = entries.length + return { enabled, failed, total } + }) + + return ( + 0}> + + + ) +} diff --git a/packages/app/src/components/session/index.ts b/packages/app/src/components/session/index.ts new file mode 100644 index 00000000000..20124b6fdef --- /dev/null +++ b/packages/app/src/components/session/index.ts @@ -0,0 +1,5 @@ +export { SessionHeader } from "./session-header" +export { SessionContextTab } from "./session-context-tab" +export { SortableTab, FileVisual } from "./session-sortable-tab" +export { SortableTerminalTab } from "./session-sortable-terminal-tab" +export { NewSessionView } from "./session-new-view" diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx new file mode 100644 index 00000000000..b415789107d --- /dev/null +++ b/packages/app/src/components/session/session-context-tab.tsx @@ -0,0 +1,432 @@ +import { createMemo, createEffect, on, onCleanup, For, Show } from "solid-js" +import type { JSX } from "solid-js" +import { useParams } from "@solidjs/router" +import { DateTime } from "luxon" +import { useSync } from "@/context/sync" +import { useLayout } from "@/context/layout" +import { checksum } from "@opencode-ai/util/encode" +import { Icon } from "@opencode-ai/ui/icon" +import { Accordion } from "@opencode-ai/ui/accordion" +import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header" +import { Code } from "@opencode-ai/ui/code" +import { Markdown } from "@opencode-ai/ui/markdown" +import type { AssistantMessage, Message, Part, UserMessage } from "@opencode-ai/sdk/v2/client" +import { useLanguage } from "@/context/language" + +interface SessionContextTabProps { + messages: () => Message[] + visibleUserMessages: () => UserMessage[] + view: () => ReturnType["view"]> + info: () => ReturnType["session"]["get"]> +} + +export function SessionContextTab(props: SessionContextTabProps) { + const params = useParams() + const sync = useSync() + const language = useLanguage() + + const ctx = createMemo(() => { + const last = props.messages().findLast((x) => { + if (x.role !== "assistant") return false + const total = x.tokens.input + x.tokens.output + x.tokens.reasoning + x.tokens.cache.read + x.tokens.cache.write + return total > 0 + }) as AssistantMessage + if (!last) return + + const provider = sync.data.provider.all.find((x) => x.id === last.providerID) + const model = provider?.models[last.modelID] + const limit = model?.limit.context + + const input = last.tokens.input + const output = last.tokens.output + const reasoning = last.tokens.reasoning + const cacheRead = last.tokens.cache.read + const cacheWrite = last.tokens.cache.write + const total = input + output + reasoning + cacheRead + cacheWrite + const usage = limit ? Math.round((total / limit) * 100) : null + + return { + message: last, + provider, + model, + limit, + input, + output, + reasoning, + cacheRead, + cacheWrite, + total, + usage, + } + }) + + const cost = createMemo(() => { + const locale = language.locale() + const total = props.messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0) + return new Intl.NumberFormat(locale, { + style: "currency", + currency: "USD", + }).format(total) + }) + + const counts = createMemo(() => { + const all = props.messages() + const user = all.reduce((count, x) => count + (x.role === "user" ? 1 : 0), 0) + const assistant = all.reduce((count, x) => count + (x.role === "assistant" ? 1 : 0), 0) + return { + all: all.length, + user, + assistant, + } + }) + + const systemPrompt = createMemo(() => { + const msg = props.visibleUserMessages().findLast((m) => !!m.system) + const system = msg?.system + if (!system) return + const trimmed = system.trim() + if (!trimmed) return + return trimmed + }) + + const number = (value: number | null | undefined) => { + if (value === undefined) return "—" + if (value === null) return "—" + return value.toLocaleString(language.locale()) + } + + const percent = (value: number | null | undefined) => { + if (value === undefined) return "—" + if (value === null) return "—" + return value.toLocaleString(language.locale()) + "%" + } + + const time = (value: number | undefined) => { + if (!value) return "—" + return DateTime.fromMillis(value).setLocale(language.locale()).toLocaleString(DateTime.DATETIME_MED) + } + + const providerLabel = createMemo(() => { + const c = ctx() + if (!c) return "—" + return c.provider?.name ?? c.message.providerID + }) + + const modelLabel = createMemo(() => { + const c = ctx() + if (!c) return "—" + if (c.model?.name) return c.model.name + return c.message.modelID + }) + + const breakdown = createMemo( + on( + () => [ctx()?.message.id, ctx()?.input, props.messages().length, systemPrompt()], + () => { + const c = ctx() + if (!c) return [] + const input = c.input + if (!input) return [] + + const out = { + system: systemPrompt()?.length ?? 0, + user: 0, + assistant: 0, + tool: 0, + } + + for (const msg of props.messages()) { + const parts = (sync.data.part[msg.id] ?? []) as Part[] + + if (msg.role === "user") { + for (const part of parts) { + if (part.type === "text") out.user += part.text.length + if (part.type === "file") out.user += part.source?.text.value.length ?? 0 + if (part.type === "agent") out.user += part.source?.value.length ?? 0 + } + continue + } + + if (msg.role === "assistant") { + for (const part of parts) { + if (part.type === "text") out.assistant += part.text.length + if (part.type === "reasoning") out.assistant += part.text.length + if (part.type === "tool") { + out.tool += Object.keys(part.state.input).length * 16 + if (part.state.status === "pending") out.tool += part.state.raw.length + if (part.state.status === "completed") out.tool += part.state.output.length + if (part.state.status === "error") out.tool += part.state.error.length + } + } + } + } + + const estimateTokens = (chars: number) => Math.ceil(chars / 4) + const system = estimateTokens(out.system) + const user = estimateTokens(out.user) + const assistant = estimateTokens(out.assistant) + const tool = estimateTokens(out.tool) + const estimated = system + user + assistant + tool + + const pct = (tokens: number) => (tokens / input) * 100 + const pctLabel = (tokens: number) => (Math.round(pct(tokens) * 10) / 10).toString() + "%" + + const build = (tokens: { system: number; user: number; assistant: number; tool: number; other: number }) => { + return [ + { + key: "system", + label: language.t("context.breakdown.system"), + tokens: tokens.system, + width: pct(tokens.system), + percent: pctLabel(tokens.system), + color: "var(--syntax-info)", + }, + { + key: "user", + label: language.t("context.breakdown.user"), + tokens: tokens.user, + width: pct(tokens.user), + percent: pctLabel(tokens.user), + color: "var(--syntax-success)", + }, + { + key: "assistant", + label: language.t("context.breakdown.assistant"), + tokens: tokens.assistant, + width: pct(tokens.assistant), + percent: pctLabel(tokens.assistant), + color: "var(--syntax-property)", + }, + { + key: "tool", + label: language.t("context.breakdown.tool"), + tokens: tokens.tool, + width: pct(tokens.tool), + percent: pctLabel(tokens.tool), + color: "var(--syntax-warning)", + }, + { + key: "other", + label: language.t("context.breakdown.other"), + tokens: tokens.other, + width: pct(tokens.other), + percent: pctLabel(tokens.other), + color: "var(--syntax-comment)", + }, + ].filter((x) => x.tokens > 0) + } + + if (estimated <= input) { + return build({ system, user, assistant, tool, other: input - estimated }) + } + + const scale = input / estimated + const scaled = { + system: Math.floor(system * scale), + user: Math.floor(user * scale), + assistant: Math.floor(assistant * scale), + tool: Math.floor(tool * scale), + } + const scaledTotal = scaled.system + scaled.user + scaled.assistant + scaled.tool + return build({ ...scaled, other: Math.max(0, input - scaledTotal) }) + }, + ), + ) + + function Stat(statProps: { label: string; value: JSX.Element }) { + return ( +
+
{statProps.label}
+
{statProps.value}
+
+ ) + } + + const stats = createMemo(() => { + const c = ctx() + const count = counts() + return [ + { label: language.t("context.stats.session"), value: props.info()?.title ?? params.id ?? "—" }, + { label: language.t("context.stats.messages"), value: count.all.toLocaleString(language.locale()) }, + { label: language.t("context.stats.provider"), value: providerLabel() }, + { label: language.t("context.stats.model"), value: modelLabel() }, + { label: language.t("context.stats.limit"), value: number(c?.limit) }, + { label: language.t("context.stats.totalTokens"), value: number(c?.total) }, + { label: language.t("context.stats.usage"), value: percent(c?.usage) }, + { label: language.t("context.stats.inputTokens"), value: number(c?.input) }, + { label: language.t("context.stats.outputTokens"), value: number(c?.output) }, + { label: language.t("context.stats.reasoningTokens"), value: number(c?.reasoning) }, + { + label: language.t("context.stats.cacheTokens"), + value: `${number(c?.cacheRead)} / ${number(c?.cacheWrite)}`, + }, + { label: language.t("context.stats.userMessages"), value: count.user.toLocaleString(language.locale()) }, + { + label: language.t("context.stats.assistantMessages"), + value: count.assistant.toLocaleString(language.locale()), + }, + { label: language.t("context.stats.totalCost"), value: cost() }, + { label: language.t("context.stats.sessionCreated"), value: time(props.info()?.time.created) }, + { label: language.t("context.stats.lastActivity"), value: time(c?.message.time.created) }, + ] satisfies { label: string; value: JSX.Element }[] + }) + + function RawMessageContent(msgProps: { message: Message }) { + const file = createMemo(() => { + const parts = (sync.data.part[msgProps.message.id] ?? []) as Part[] + const contents = JSON.stringify({ message: msgProps.message, parts }, null, 2) + return { + name: `${msgProps.message.role}-${msgProps.message.id}.json`, + contents, + cacheKey: checksum(contents), + } + }) + + return + } + + function RawMessage(msgProps: { message: Message }) { + return ( + + + +
+
+ {msgProps.message.role} • {msgProps.message.id} +
+
+
{time(msgProps.message.time.created)}
+ +
+
+
+
+ +
+ +
+
+
+ ) + } + + let scroll: HTMLDivElement | undefined + let frame: number | undefined + let pending: { x: number; y: number } | undefined + + const restoreScroll = (retries = 0) => { + const el = scroll + if (!el) return + + const s = props.view()?.scroll("context") + if (!s) return + + // Wait for content to be scrollable - content may not have rendered yet + if (el.scrollHeight <= el.clientHeight && retries < 10) { + requestAnimationFrame(() => restoreScroll(retries + 1)) + return + } + + if (el.scrollTop !== s.y) el.scrollTop = s.y + if (el.scrollLeft !== s.x) el.scrollLeft = s.x + } + + const handleScroll = (event: Event & { currentTarget: HTMLDivElement }) => { + pending = { + x: event.currentTarget.scrollLeft, + y: event.currentTarget.scrollTop, + } + if (frame !== undefined) return + + frame = requestAnimationFrame(() => { + frame = undefined + + const next = pending + pending = undefined + if (!next) return + + props.view().setScroll("context", next) + }) + } + + createEffect( + on( + () => props.messages().length, + () => { + requestAnimationFrame(restoreScroll) + }, + { defer: true }, + ), + ) + + onCleanup(() => { + if (frame === undefined) return + cancelAnimationFrame(frame) + }) + + return ( +
{ + scroll = el + restoreScroll() + }} + onScroll={handleScroll} + > +
+
+ {(stat) => } +
+ + 0}> +
+
{language.t("context.breakdown.title")}
+
+ + {(segment) => ( +
+ )} + +
+
+ + {(segment) => ( +
+
+
{segment.label}
+
{segment.percent}
+
+ )} + +
+ +
+ + + + {(prompt) => ( +
+
{language.t("context.systemPrompt.title")}
+
+ +
+
+ )} +
+ +
+
{language.t("context.rawMessages.title")}
+ + {(message) => } + +
+
+
+ ) +} diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx new file mode 100644 index 00000000000..a76734a691d --- /dev/null +++ b/packages/app/src/components/session/session-header.tsx @@ -0,0 +1,343 @@ +import { createEffect, createMemo, onCleanup, Show } from "solid-js" +import { createStore } from "solid-js/store" +import { Portal } from "solid-js/web" +import { useParams } from "@solidjs/router" +import { useLayout } from "@/context/layout" +import { useCommand } from "@/context/command" +import { useLanguage } from "@/context/language" +// import { useServer } from "@/context/server" +// import { useDialog } from "@opencode-ai/ui/context/dialog" +import { usePlatform } from "@/context/platform" +import { useSync } from "@/context/sync" +import { useGlobalSDK } from "@/context/global-sdk" +import { getFilename } from "@opencode-ai/util/path" +import { base64Decode } from "@opencode-ai/util/encode" + +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Button } from "@opencode-ai/ui/button" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { Popover } from "@opencode-ai/ui/popover" +import { TextField } from "@opencode-ai/ui/text-field" +import { Keybind } from "@opencode-ai/ui/keybind" + +export function SessionHeader() { + const globalSDK = useGlobalSDK() + const layout = useLayout() + const params = useParams() + const command = useCommand() + // const server = useServer() + // const dialog = useDialog() + const sync = useSync() + const platform = usePlatform() + const language = useLanguage() + + const projectDirectory = createMemo(() => base64Decode(params.dir ?? "")) + const project = createMemo(() => { + const directory = projectDirectory() + if (!directory) return + return layout.projects.list().find((p) => p.worktree === directory || p.sandboxes?.includes(directory)) + }) + const name = createMemo(() => { + const current = project() + if (current) return current.name || getFilename(current.worktree) + return getFilename(projectDirectory()) + }) + const hotkey = createMemo(() => command.keybind("file.open")) + + const currentSession = createMemo(() => sync.data.session.find((s) => s.id === params.id)) + const shareEnabled = createMemo(() => sync.data.config.share !== "disabled") + const showShare = createMemo(() => shareEnabled() && !!currentSession()) + const showReview = createMemo(() => !!currentSession()) + const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) + const view = createMemo(() => layout.view(sessionKey())) + + const [state, setState] = createStore({ + share: false, + unshare: false, + copied: false, + timer: undefined as number | undefined, + }) + const shareUrl = createMemo(() => currentSession()?.share?.url) + + createEffect(() => { + const url = shareUrl() + if (url) return + if (state.timer) window.clearTimeout(state.timer) + setState({ copied: false, timer: undefined }) + }) + + onCleanup(() => { + if (state.timer) window.clearTimeout(state.timer) + }) + + function shareSession() { + const session = currentSession() + if (!session || state.share) return + setState("share", true) + globalSDK.client.session + .share({ sessionID: session.id, directory: projectDirectory() }) + .catch((error) => { + console.error("Failed to share session", error) + }) + .finally(() => { + setState("share", false) + }) + } + + function unshareSession() { + const session = currentSession() + if (!session || state.unshare) return + setState("unshare", true) + globalSDK.client.session + .unshare({ sessionID: session.id, directory: projectDirectory() }) + .catch((error) => { + console.error("Failed to unshare session", error) + }) + .finally(() => { + setState("unshare", false) + }) + } + + function copyLink() { + const url = shareUrl() + if (!url) return + navigator.clipboard + .writeText(url) + .then(() => { + if (state.timer) window.clearTimeout(state.timer) + setState("copied", true) + const timer = window.setTimeout(() => { + setState("copied", false) + setState("timer", undefined) + }, 3000) + setState("timer", timer) + }) + .catch((error) => { + console.error("Failed to copy share link", error) + }) + } + + function viewShare() { + const url = shareUrl() + if (!url) return + platform.openLink(url) + } + + const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center")) + const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right")) + + return ( + <> + + {(mount) => ( + + + + )} + + + {(mount) => ( + +
+ {/* */} +
+ + +
+ +
+ +
+ + +
+ } + > +
+ +
+ + +
+
+ +
+ + +
+
+
+ + )} + + + ) +} diff --git a/packages/app/src/components/session/session-new-view.tsx b/packages/app/src/components/session/session-new-view.tsx new file mode 100644 index 00000000000..f7f422fc5ea --- /dev/null +++ b/packages/app/src/components/session/session-new-view.tsx @@ -0,0 +1,93 @@ +import { Show, createMemo } from "solid-js" +import { DateTime } from "luxon" +import { useSync } from "@/context/sync" +import { useLanguage } from "@/context/language" +import { Icon } from "@opencode-ai/ui/icon" +import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { Select } from "@opencode-ai/ui/select" + +const MAIN_WORKTREE = "main" +const CREATE_WORKTREE = "create" + +interface NewSessionViewProps { + worktree: string + onWorktreeChange: (value: string) => void +} + +export function NewSessionView(props: NewSessionViewProps) { + const sync = useSync() + const language = useLanguage() + + const sandboxes = createMemo(() => sync.project?.sandboxes ?? []) + const options = createMemo(() => [MAIN_WORKTREE, ...sandboxes(), CREATE_WORKTREE]) + const current = createMemo(() => { + const selection = props.worktree + if (options().includes(selection)) return selection + return MAIN_WORKTREE + }) + const projectRoot = createMemo(() => sync.project?.worktree ?? sync.data.path.directory) + const isWorktree = createMemo(() => { + const project = sync.project + if (!project) return false + return sync.data.path.directory !== project.worktree + }) + + const label = (value: string) => { + if (value === MAIN_WORKTREE) { + if (isWorktree()) return language.t("session.new.worktree.main") + const branch = sync.data.vcs?.branch + if (branch) return language.t("session.new.worktree.mainWithBranch", { branch }) + return language.t("session.new.worktree.main") + } + + if (value === CREATE_WORKTREE) return language.t("session.new.worktree.create") + + return getFilename(value) + } + + return ( +
+
{language.t("command.session.new")}
+
+ +
+ {getDirectory(projectRoot())} + {getFilename(projectRoot())} +
+
+
+ + setTitle(e.currentTarget.value)} + onBlur={save} + onKeyDown={keydown} + onMouseDown={(e) => e.stopPropagation()} + class="bg-transparent border-none outline-none text-sm min-w-0 flex-1" + /> +
+ + + + + + + {language.t("common.rename")} + + + + {language.t("common.close")} + + + + +
+
+ ) +} diff --git a/packages/app/src/components/settings-agents.tsx b/packages/app/src/components/settings-agents.tsx new file mode 100644 index 00000000000..e68f1e59c53 --- /dev/null +++ b/packages/app/src/components/settings-agents.tsx @@ -0,0 +1,15 @@ +import { Component } from "solid-js" +import { useLanguage } from "@/context/language" + +export const SettingsAgents: Component = () => { + const language = useLanguage() + + return ( +
+
+

{language.t("settings.agents.title")}

+

{language.t("settings.agents.description")}

+
+
+ ) +} diff --git a/packages/app/src/components/settings-commands.tsx b/packages/app/src/components/settings-commands.tsx new file mode 100644 index 00000000000..cf796d0aa7a --- /dev/null +++ b/packages/app/src/components/settings-commands.tsx @@ -0,0 +1,15 @@ +import { Component } from "solid-js" +import { useLanguage } from "@/context/language" + +export const SettingsCommands: Component = () => { + const language = useLanguage() + + return ( +
+
+

{language.t("settings.commands.title")}

+

{language.t("settings.commands.description")}

+
+
+ ) +} diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx new file mode 100644 index 00000000000..c3cc2760142 --- /dev/null +++ b/packages/app/src/components/settings-general.tsx @@ -0,0 +1,296 @@ +import { Component, createMemo, type JSX } from "solid-js" +import { Select } from "@opencode-ai/ui/select" +import { Switch } from "@opencode-ai/ui/switch" +import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme" +import { useLanguage } from "@/context/language" +import { useSettings, monoFontFamily } from "@/context/settings" +import { playSound, SOUND_OPTIONS } from "@/utils/sound" +import { Link } from "./link" + +export const SettingsGeneral: Component = () => { + const theme = useTheme() + const language = useLanguage() + const settings = useSettings() + + const themeOptions = createMemo(() => + Object.entries(theme.themes()).map(([id, def]) => ({ id, name: def.name ?? id })), + ) + + const colorSchemeOptions = createMemo((): { value: ColorScheme; label: string }[] => [ + { value: "system", label: language.t("theme.scheme.system") }, + { value: "light", label: language.t("theme.scheme.light") }, + { value: "dark", label: language.t("theme.scheme.dark") }, + ]) + + const languageOptions = createMemo(() => + language.locales.map((locale) => ({ + value: locale, + label: language.label(locale), + })), + ) + + const fontOptions = [ + { value: "ibm-plex-mono", label: "font.option.ibmPlexMono" }, + { value: "cascadia-code", label: "font.option.cascadiaCode" }, + { value: "fira-code", label: "font.option.firaCode" }, + { value: "hack", label: "font.option.hack" }, + { value: "inconsolata", label: "font.option.inconsolata" }, + { value: "intel-one-mono", label: "font.option.intelOneMono" }, + { value: "jetbrains-mono", label: "font.option.jetbrainsMono" }, + { value: "meslo-lgs", label: "font.option.mesloLgs" }, + { value: "roboto-mono", label: "font.option.robotoMono" }, + { value: "source-code-pro", label: "font.option.sourceCodePro" }, + { value: "ubuntu-mono", label: "font.option.ubuntuMono" }, + ] as const + const fontOptionsList = [...fontOptions] + + const soundOptions = [...SOUND_OPTIONS] + + return ( +
+
+
+

{language.t("settings.tab.general")}

+
+
+ +
+ {/* Appearance Section */} +
+

{language.t("settings.general.section.appearance")}

+ +
+ + o.value === theme.colorScheme())} + value={(o) => o.value} + label={(o) => o.label} + onSelect={(option) => option && theme.setColorScheme(option.value)} + onHighlight={(option) => { + if (!option) return + theme.previewColorScheme(option.value) + return () => theme.cancelPreview() + }} + variant="secondary" + size="small" + triggerVariant="settings" + /> + + + + {language.t("settings.general.row.theme.description")}{" "} + {language.t("common.learnMore")} + + } + > + o.value === settings.appearance.font())} + value={(o) => o.value} + label={(o) => language.t(o.label)} + onSelect={(option) => option && settings.appearance.setFont(option.value)} + variant="secondary" + size="small" + triggerVariant="settings" + triggerStyle={{ "font-family": monoFontFamily(settings.appearance.font()), "min-width": "180px" }} + > + {(option) => ( + + {option ? language.t(option.label) : ""} + + )} + + +
+
+ + {/* System notifications Section */} +
+

{language.t("settings.general.section.notifications")}

+ +
+ + settings.notifications.setAgent(checked)} + /> + + + + settings.notifications.setPermissions(checked)} + /> + + + + settings.notifications.setErrors(checked)} + /> + +
+
+ + {/* Sound effects Section */} +
+

{language.t("settings.general.section.sounds")}

+ +
+ + o.id === settings.sounds.permissions())} + value={(o) => o.id} + label={(o) => language.t(o.label)} + onHighlight={(option) => { + if (!option) return + playSound(option.src) + }} + onSelect={(option) => { + if (!option) return + settings.sounds.setPermissions(option.id) + playSound(option.src) + }} + variant="secondary" + size="small" + triggerVariant="settings" + /> + + + + o.value === actionFor(item.id))} + value={(o) => o.value} + label={(o) => o.label} + onSelect={(option) => option && setPermission(item.id, option.value)} + variant="secondary" + size="small" + triggerVariant="settings" + /> + + )} + +
+
+
+
+ ) +} + +interface SettingsRowProps { + title: string + description: string + children: JSX.Element +} + +const SettingsRow: Component = (props) => { + return ( +
+
+ {props.title} + {props.description} +
+
{props.children}
+
+ ) +} diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx new file mode 100644 index 00000000000..7b6ca193924 --- /dev/null +++ b/packages/app/src/components/settings-providers.tsx @@ -0,0 +1,15 @@ +import { Component } from "solid-js" +import { useLanguage } from "@/context/language" + +export const SettingsProviders: Component = () => { + const language = useLanguage() + + return ( +
+
+

{language.t("settings.providers.title")}

+

{language.t("settings.providers.description")}

+
+
+ ) +} diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx new file mode 100644 index 00000000000..6bedcfae2ce --- /dev/null +++ b/packages/app/src/components/terminal.tsx @@ -0,0 +1,315 @@ +import type { Ghostty, Terminal as Term, FitAddon } from "ghostty-web" +import { ComponentProps, createEffect, createSignal, onCleanup, onMount, splitProps } from "solid-js" +import { useSDK } from "@/context/sdk" +import { monoFontFamily, useSettings } from "@/context/settings" +import { SerializeAddon } from "@/addons/serialize" +import { LocalPTY } from "@/context/terminal" +import { resolveThemeVariant, useTheme, withAlpha, type HexColor } from "@opencode-ai/ui/theme" + +export interface TerminalProps extends ComponentProps<"div"> { + pty: LocalPTY + onSubmit?: () => void + onCleanup?: (pty: LocalPTY) => void + onConnect?: () => void + onConnectError?: (error: unknown) => void +} + +type TerminalColors = { + background: string + foreground: string + cursor: string + selectionBackground: string +} + +const DEFAULT_TERMINAL_COLORS: Record<"light" | "dark", TerminalColors> = { + light: { + background: "#fcfcfc", + foreground: "#211e1e", + cursor: "#211e1e", + selectionBackground: withAlpha("#211e1e", 0.2), + }, + dark: { + background: "#191515", + foreground: "#d4d4d4", + cursor: "#d4d4d4", + selectionBackground: withAlpha("#d4d4d4", 0.25), + }, +} + +export const Terminal = (props: TerminalProps) => { + const sdk = useSDK() + const settings = useSettings() + const theme = useTheme() + let container!: HTMLDivElement + const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnect", "onConnectError"]) + let ws: WebSocket | undefined + let term: Term | undefined + let ghostty: Ghostty + let serializeAddon: SerializeAddon + let fitAddon: FitAddon + let handleResize: () => void + let handleTextareaFocus: () => void + let handleTextareaBlur: () => void + let reconnect: number | undefined + let disposed = false + + const getTerminalColors = (): TerminalColors => { + const mode = theme.mode() + const fallback = DEFAULT_TERMINAL_COLORS[mode] + const currentTheme = theme.themes()[theme.themeId()] + if (!currentTheme) return fallback + const variant = mode === "dark" ? currentTheme.dark : currentTheme.light + if (!variant?.seeds) return fallback + const resolved = resolveThemeVariant(variant, mode === "dark") + const text = resolved["text-stronger"] ?? fallback.foreground + const background = resolved["background-stronger"] ?? fallback.background + const alpha = mode === "dark" ? 0.25 : 0.2 + const base = text.startsWith("#") ? (text as HexColor) : (fallback.foreground as HexColor) + const selectionBackground = withAlpha(base, alpha) + return { + background, + foreground: text, + cursor: text, + selectionBackground, + } + } + + const [terminalColors, setTerminalColors] = createSignal(getTerminalColors()) + + createEffect(() => { + const colors = getTerminalColors() + setTerminalColors(colors) + if (!term) return + const setOption = (term as unknown as { setOption?: (key: string, value: TerminalColors) => void }).setOption + if (!setOption) return + setOption("theme", colors) + }) + + createEffect(() => { + const font = monoFontFamily(settings.appearance.font()) + if (!term) return + const setOption = (term as unknown as { setOption?: (key: string, value: string) => void }).setOption + if (!setOption) return + setOption("fontFamily", font) + }) + + const focusTerminal = () => { + const t = term + if (!t) return + t.focus() + setTimeout(() => t.textarea?.focus(), 0) + } + const handlePointerDown = () => { + const activeElement = document.activeElement + if (activeElement instanceof HTMLElement && activeElement !== container) { + activeElement.blur() + } + focusTerminal() + } + + onMount(async () => { + const mod = await import("ghostty-web") + ghostty = await mod.Ghostty.load() + + const url = new URL(sdk.url + `/pty/${local.pty.id}/connect?directory=${encodeURIComponent(sdk.directory)}`) + if (window.__OPENCODE__?.serverPassword) { + url.username = "opencode" + url.password = window.__OPENCODE__?.serverPassword + } + const socket = new WebSocket(url) + ws = socket + + const t = new mod.Terminal({ + cursorBlink: true, + cursorStyle: "bar", + fontSize: 14, + fontFamily: monoFontFamily(settings.appearance.font()), + allowTransparency: true, + theme: terminalColors(), + scrollback: 10_000, + ghostty, + }) + term = t + + const copy = () => { + const selection = t.getSelection() + if (!selection) return false + + const body = document.body + if (body) { + const textarea = document.createElement("textarea") + textarea.value = selection + textarea.setAttribute("readonly", "") + textarea.style.position = "fixed" + textarea.style.opacity = "0" + body.appendChild(textarea) + textarea.select() + const copied = document.execCommand("copy") + body.removeChild(textarea) + if (copied) return true + } + + const clipboard = navigator.clipboard + if (clipboard?.writeText) { + clipboard.writeText(selection).catch(() => {}) + return true + } + + return false + } + + t.attachCustomKeyEventHandler((event) => { + const key = event.key.toLowerCase() + + if (event.ctrlKey && event.shiftKey && !event.metaKey && key === "c") { + copy() + return true + } + + if (event.metaKey && !event.ctrlKey && !event.altKey && key === "c") { + if (!t.hasSelection()) return true + copy() + return true + } + + // allow for ctrl-` to toggle terminal in parent + if (event.ctrlKey && key === "`") { + return true + } + + return false + }) + + fitAddon = new mod.FitAddon() + serializeAddon = new SerializeAddon() + t.loadAddon(serializeAddon) + t.loadAddon(fitAddon) + + t.open(container) + container.addEventListener("pointerdown", handlePointerDown) + + handleTextareaFocus = () => { + t.options.cursorBlink = true + } + handleTextareaBlur = () => { + t.options.cursorBlink = false + } + + t.textarea?.addEventListener("focus", handleTextareaFocus) + t.textarea?.addEventListener("blur", handleTextareaBlur) + + focusTerminal() + + if (local.pty.buffer) { + if (local.pty.rows && local.pty.cols) { + t.resize(local.pty.cols, local.pty.rows) + } + t.write(local.pty.buffer, () => { + if (local.pty.scrollY) { + t.scrollToLine(local.pty.scrollY) + } + fitAddon.fit() + }) + } + + fitAddon.observeResize() + handleResize = () => fitAddon.fit() + window.addEventListener("resize", handleResize) + t.onResize(async (size) => { + if (socket.readyState === WebSocket.OPEN) { + await sdk.client.pty + .update({ + ptyID: local.pty.id, + size: { + cols: size.cols, + rows: size.rows, + }, + }) + .catch(() => {}) + } + }) + t.onData((data) => { + if (socket.readyState === WebSocket.OPEN) { + socket.send(data) + } + }) + t.onKey((key) => { + if (key.key == "Enter") { + props.onSubmit?.() + } + }) + // t.onScroll((ydisp) => { + // console.log("Scroll position:", ydisp) + // }) + socket.addEventListener("open", () => { + local.onConnect?.() + sdk.client.pty + .update({ + ptyID: local.pty.id, + size: { + cols: t.cols, + rows: t.rows, + }, + }) + .catch(() => {}) + }) + socket.addEventListener("message", (event) => { + t.write(event.data) + }) + socket.addEventListener("error", (error) => { + if (disposed) return + console.error("WebSocket error:", error) + local.onConnectError?.(error) + }) + socket.addEventListener("close", (event) => { + if (disposed) return + // Normal closure (code 1000) means PTY process exited - server event handles cleanup + // For other codes (network issues, server restart), trigger error handler + if (event.code !== 1000) { + local.onConnectError?.(new Error(`WebSocket closed abnormally: ${event.code}`)) + } + }) + }) + + onCleanup(() => { + disposed = true + if (handleResize) { + window.removeEventListener("resize", handleResize) + } + container.removeEventListener("pointerdown", handlePointerDown) + term?.textarea?.removeEventListener("focus", handleTextareaFocus) + term?.textarea?.removeEventListener("blur", handleTextareaBlur) + + const t = term + if (serializeAddon && props.onCleanup && t) { + const buffer = serializeAddon.serialize() + props.onCleanup({ + ...local.pty, + buffer, + rows: t.rows, + cols: t.cols, + scrollY: t.getViewportY(), + }) + } + + ws?.close() + t?.dispose() + }) + + return ( +
+ ) +} diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx new file mode 100644 index 00000000000..f631305b4ec --- /dev/null +++ b/packages/app/src/components/titlebar.tsx @@ -0,0 +1,156 @@ +import { createEffect, createMemo, Show } from "solid-js" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Icon } from "@opencode-ai/ui/icon" +import { Button } from "@opencode-ai/ui/button" +import { TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { useTheme } from "@opencode-ai/ui/theme" + +import { useLayout } from "@/context/layout" +import { usePlatform } from "@/context/platform" +import { useCommand } from "@/context/command" +import { useLanguage } from "@/context/language" + +export function Titlebar() { + const layout = useLayout() + const platform = usePlatform() + const command = useCommand() + const language = useLanguage() + const theme = useTheme() + + const mac = createMemo(() => platform.platform === "desktop" && platform.os === "macos") + const windows = createMemo(() => platform.platform === "desktop" && platform.os === "windows") + const reserve = createMemo( + () => platform.platform === "desktop" && (platform.os === "windows" || platform.os === "linux"), + ) + const web = createMemo(() => platform.platform === "web") + + const getWin = () => { + if (platform.platform !== "desktop") return + + const tauri = ( + window as unknown as { + __TAURI__?: { window?: { getCurrentWindow?: () => { startDragging?: () => Promise } } } + } + ).__TAURI__ + if (!tauri?.window?.getCurrentWindow) return + + return tauri.window.getCurrentWindow() + } + + createEffect(() => { + if (platform.platform !== "desktop") return + + const scheme = theme.colorScheme() + const value = scheme === "system" ? null : scheme + + const tauri = (window as unknown as { __TAURI__?: { webviewWindow?: { getCurrentWebviewWindow?: () => unknown } } }) + .__TAURI__ + const get = tauri?.webviewWindow?.getCurrentWebviewWindow + if (!get) return + + const win = get() as { setTheme?: (theme?: "light" | "dark" | null) => Promise } + if (!win.setTheme) return + + void win.setTheme(value).catch(() => undefined) + }) + + const interactive = (target: EventTarget | null) => { + if (!(target instanceof Element)) return false + + const selector = + "button, a, input, textarea, select, option, [role='button'], [role='menuitem'], [contenteditable='true'], [contenteditable='']" + + return !!target.closest(selector) + } + + const drag = (e: MouseEvent) => { + if (platform.platform !== "desktop") return + if (e.buttons !== 1) return + if (interactive(e.target)) return + + const win = getWin() + if (!win?.startDragging) return + + e.preventDefault() + void win.startDragging().catch(() => undefined) + } + + return ( +
+
+ +
+
+ +
+ + +
+ +
+
+ + + +
+
+
+ +
+ +
+
+
+
+
+ ) +} diff --git a/packages/app/src/context/command.tsx b/packages/app/src/context/command.tsx new file mode 100644 index 00000000000..39bd11a1bb0 --- /dev/null +++ b/packages/app/src/context/command.tsx @@ -0,0 +1,308 @@ +import { createEffect, createMemo, createSignal, onCleanup, onMount, type Accessor } from "solid-js" +import { createStore } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useLanguage } from "@/context/language" +import { useSettings } from "@/context/settings" +import { Persist, persisted } from "@/utils/persist" + +const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) + +const PALETTE_ID = "command.palette" +const DEFAULT_PALETTE_KEYBIND = "mod+shift+p" +const SUGGESTED_PREFIX = "suggested." + +function actionId(id: string) { + if (!id.startsWith(SUGGESTED_PREFIX)) return id + return id.slice(SUGGESTED_PREFIX.length) +} + +function normalizeKey(key: string) { + if (key === ",") return "comma" + if (key === "+") return "plus" + if (key === " ") return "space" + return key.toLowerCase() +} + +export type KeybindConfig = string + +export interface Keybind { + key: string + ctrl: boolean + meta: boolean + shift: boolean + alt: boolean +} + +export interface CommandOption { + id: string + title: string + description?: string + category?: string + keybind?: KeybindConfig + slash?: string + suggested?: boolean + disabled?: boolean + onSelect?: (source?: "palette" | "keybind" | "slash") => void + onHighlight?: () => (() => void) | void +} + +export type CommandCatalogItem = { + title: string + description?: string + category?: string + keybind?: KeybindConfig + slash?: string +} + +export function parseKeybind(config: string): Keybind[] { + if (!config || config === "none") return [] + + return config.split(",").map((combo) => { + const parts = combo.trim().toLowerCase().split("+") + const keybind: Keybind = { + key: "", + ctrl: false, + meta: false, + shift: false, + alt: false, + } + + for (const part of parts) { + switch (part) { + case "ctrl": + case "control": + keybind.ctrl = true + break + case "meta": + case "cmd": + case "command": + keybind.meta = true + break + case "mod": + if (IS_MAC) keybind.meta = true + else keybind.ctrl = true + break + case "alt": + case "option": + keybind.alt = true + break + case "shift": + keybind.shift = true + break + default: + keybind.key = part + break + } + } + + return keybind + }) +} + +export function matchKeybind(keybinds: Keybind[], event: KeyboardEvent): boolean { + const eventKey = normalizeKey(event.key) + + for (const kb of keybinds) { + const keyMatch = kb.key === eventKey + const ctrlMatch = kb.ctrl === (event.ctrlKey || false) + const metaMatch = kb.meta === (event.metaKey || false) + const shiftMatch = kb.shift === (event.shiftKey || false) + const altMatch = kb.alt === (event.altKey || false) + + if (keyMatch && ctrlMatch && metaMatch && shiftMatch && altMatch) { + return true + } + } + + return false +} + +export function formatKeybind(config: string): string { + if (!config || config === "none") return "" + + const keybinds = parseKeybind(config) + if (keybinds.length === 0) return "" + + const kb = keybinds[0] + const parts: string[] = [] + + if (kb.ctrl) parts.push(IS_MAC ? "⌃" : "Ctrl") + if (kb.alt) parts.push(IS_MAC ? "⌥" : "Alt") + if (kb.shift) parts.push(IS_MAC ? "⇧" : "Shift") + if (kb.meta) parts.push(IS_MAC ? "⌘" : "Meta") + + if (kb.key) { + const keys: Record = { + arrowup: "↑", + arrowdown: "↓", + arrowleft: "←", + arrowright: "→", + comma: ",", + plus: "+", + space: "Space", + } + const key = kb.key.toLowerCase() + const displayKey = keys[key] ?? (key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1)) + parts.push(displayKey) + } + + return IS_MAC ? parts.join("") : parts.join("+") +} + +export const { use: useCommand, provider: CommandProvider } = createSimpleContext({ + name: "Command", + init: () => { + const dialog = useDialog() + const settings = useSettings() + const language = useLanguage() + const [registrations, setRegistrations] = createSignal[]>([]) + const [suspendCount, setSuspendCount] = createSignal(0) + + const [catalog, setCatalog, _, catalogReady] = persisted( + Persist.global("command.catalog.v1"), + createStore>({}), + ) + + const bind = (id: string, def: KeybindConfig | undefined) => { + const custom = settings.keybinds.get(actionId(id)) + const config = custom ?? def + if (!config || config === "none") return + return config + } + + const registered = createMemo(() => { + const seen = new Set() + const all: CommandOption[] = [] + + for (const reg of registrations()) { + for (const opt of reg()) { + if (seen.has(opt.id)) continue + seen.add(opt.id) + all.push(opt) + } + } + + return all + }) + + createEffect(() => { + if (!catalogReady()) return + + for (const opt of registered()) { + const id = actionId(opt.id) + setCatalog(id, { + title: opt.title, + description: opt.description, + category: opt.category, + keybind: opt.keybind, + slash: opt.slash, + }) + } + }) + + const catalogOptions = createMemo(() => Object.entries(catalog).map(([id, meta]) => ({ id, ...meta }))) + + const options = createMemo(() => { + const resolved = registered().map((opt) => ({ + ...opt, + keybind: bind(opt.id, opt.keybind), + })) + + const suggested = resolved.filter((x) => x.suggested && !x.disabled) + + return [ + ...suggested.map((x) => ({ + ...x, + id: SUGGESTED_PREFIX + x.id, + category: language.t("command.category.suggested"), + })), + ...resolved, + ] + }) + + const suspended = () => suspendCount() > 0 + + const run = (id: string, source?: "palette" | "keybind" | "slash") => { + for (const option of options()) { + if (option.id === id || option.id === "suggested." + id) { + option.onSelect?.(source) + return + } + } + } + + const showPalette = () => { + run("file.open", "palette") + } + + const handleKeyDown = (event: KeyboardEvent) => { + if (suspended() || dialog.active) return + + const paletteKeybinds = parseKeybind(settings.keybinds.get(PALETTE_ID) ?? DEFAULT_PALETTE_KEYBIND) + if (matchKeybind(paletteKeybinds, event)) { + event.preventDefault() + showPalette() + return + } + + for (const option of options()) { + if (option.disabled) continue + if (!option.keybind) continue + + const keybinds = parseKeybind(option.keybind) + if (matchKeybind(keybinds, event)) { + event.preventDefault() + option.onSelect?.("keybind") + return + } + } + } + + onMount(() => { + document.addEventListener("keydown", handleKeyDown) + }) + + onCleanup(() => { + document.removeEventListener("keydown", handleKeyDown) + }) + + return { + register(cb: () => CommandOption[]) { + const results = createMemo(cb) + setRegistrations((arr) => [results, ...arr]) + onCleanup(() => { + setRegistrations((arr) => arr.filter((x) => x !== results)) + }) + }, + trigger(id: string, source?: "palette" | "keybind" | "slash") { + run(id, source) + }, + keybind(id: string) { + if (id === PALETTE_ID) { + return formatKeybind(settings.keybinds.get(PALETTE_ID) ?? DEFAULT_PALETTE_KEYBIND) + } + + const base = actionId(id) + const option = options().find((x) => actionId(x.id) === base) + if (option?.keybind) return formatKeybind(option.keybind) + + const meta = catalog[base] + const config = bind(base, meta?.keybind) + if (!config) return "" + return formatKeybind(config) + }, + show: showPalette, + keybinds(enabled: boolean) { + setSuspendCount((count) => count + (enabled ? -1 : 1)) + }, + suspended, + get catalog() { + return catalogOptions() + }, + get options() { + return options() + }, + } + }, +}) diff --git a/packages/app/src/context/file.tsx b/packages/app/src/context/file.tsx new file mode 100644 index 00000000000..5ea4993879c --- /dev/null +++ b/packages/app/src/context/file.tsx @@ -0,0 +1,395 @@ +import { createEffect, createMemo, createRoot, onCleanup } from "solid-js" +import { createStore, produce } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import type { FileContent } from "@opencode-ai/sdk/v2" +import { showToast } from "@opencode-ai/ui/toast" +import { useParams } from "@solidjs/router" +import { getFilename } from "@opencode-ai/util/path" +import { useSDK } from "./sdk" +import { useSync } from "./sync" +import { useLanguage } from "@/context/language" +import { Persist, persisted } from "@/utils/persist" + +export type FileSelection = { + startLine: number + startChar: number + endLine: number + endChar: number +} + +export type SelectedLineRange = { + start: number + end: number + side?: "additions" | "deletions" + endSide?: "additions" | "deletions" +} + +export type FileViewState = { + scrollTop?: number + scrollLeft?: number + selectedLines?: SelectedLineRange | null +} + +export type FileState = { + path: string + name: string + loaded?: boolean + loading?: boolean + error?: string + content?: FileContent +} + +function stripFileProtocol(input: string) { + if (!input.startsWith("file://")) return input + return input.slice("file://".length) +} + +function stripQueryAndHash(input: string) { + const hashIndex = input.indexOf("#") + const queryIndex = input.indexOf("?") + + if (hashIndex !== -1 && queryIndex !== -1) { + return input.slice(0, Math.min(hashIndex, queryIndex)) + } + + if (hashIndex !== -1) return input.slice(0, hashIndex) + if (queryIndex !== -1) return input.slice(0, queryIndex) + return input +} + +export function selectionFromLines(range: SelectedLineRange): FileSelection { + const startLine = Math.min(range.start, range.end) + const endLine = Math.max(range.start, range.end) + return { + startLine, + endLine, + startChar: 0, + endChar: 0, + } +} + +function normalizeSelectedLines(range: SelectedLineRange): SelectedLineRange { + if (range.start <= range.end) return range + + const startSide = range.side + const endSide = range.endSide ?? startSide + + return { + ...range, + start: range.end, + end: range.start, + side: endSide, + endSide: startSide !== endSide ? startSide : undefined, + } +} + +const WORKSPACE_KEY = "__workspace__" +const MAX_FILE_VIEW_SESSIONS = 20 +const MAX_VIEW_FILES = 500 + +type ViewSession = ReturnType + +type ViewCacheEntry = { + value: ViewSession + dispose: VoidFunction +} + +function createViewSession(dir: string, id: string | undefined) { + const legacyViewKey = `${dir}/file${id ? "/" + id : ""}.v1` + + const [view, setView, _, ready] = persisted( + Persist.scoped(dir, id, "file-view", [legacyViewKey]), + createStore<{ + file: Record + }>({ + file: {}, + }), + ) + + const meta = { pruned: false } + + const pruneView = (keep?: string) => { + const keys = Object.keys(view.file) + if (keys.length <= MAX_VIEW_FILES) return + + const drop = keys.filter((key) => key !== keep).slice(0, keys.length - MAX_VIEW_FILES) + if (drop.length === 0) return + + setView( + produce((draft) => { + for (const key of drop) { + delete draft.file[key] + } + }), + ) + } + + createEffect(() => { + if (!ready()) return + if (meta.pruned) return + meta.pruned = true + pruneView() + }) + + const scrollTop = (path: string) => view.file[path]?.scrollTop + const scrollLeft = (path: string) => view.file[path]?.scrollLeft + const selectedLines = (path: string) => view.file[path]?.selectedLines + + const setScrollTop = (path: string, top: number) => { + setView("file", path, (current) => { + if (current?.scrollTop === top) return current + return { + ...(current ?? {}), + scrollTop: top, + } + }) + pruneView(path) + } + + const setScrollLeft = (path: string, left: number) => { + setView("file", path, (current) => { + if (current?.scrollLeft === left) return current + return { + ...(current ?? {}), + scrollLeft: left, + } + }) + pruneView(path) + } + + const setSelectedLines = (path: string, range: SelectedLineRange | null) => { + const next = range ? normalizeSelectedLines(range) : null + setView("file", path, (current) => { + if (current?.selectedLines === next) return current + return { + ...(current ?? {}), + selectedLines: next, + } + }) + pruneView(path) + } + + return { + ready, + scrollTop, + scrollLeft, + selectedLines, + setScrollTop, + setScrollLeft, + setSelectedLines, + } +} + +export const { use: useFile, provider: FileProvider } = createSimpleContext({ + name: "File", + gate: false, + init: () => { + const sdk = useSDK() + const sync = useSync() + const params = useParams() + const language = useLanguage() + + const directory = createMemo(() => sync.data.path.directory) + + function normalize(input: string) { + const root = directory() + const prefix = root.endsWith("/") ? root : root + "/" + + let path = stripQueryAndHash(stripFileProtocol(input)) + + if (path.startsWith(prefix)) { + path = path.slice(prefix.length) + } + + if (path.startsWith(root)) { + path = path.slice(root.length) + } + + if (path.startsWith("./")) { + path = path.slice(2) + } + + if (path.startsWith("/")) { + path = path.slice(1) + } + + return path + } + + function tab(input: string) { + const path = normalize(input) + return `file://${path}` + } + + function pathFromTab(tabValue: string) { + if (!tabValue.startsWith("file://")) return + return normalize(tabValue) + } + + const inflight = new Map>() + + const [store, setStore] = createStore<{ + file: Record + }>({ + file: {}, + }) + + const viewCache = new Map() + + const disposeViews = () => { + for (const entry of viewCache.values()) { + entry.dispose() + } + viewCache.clear() + } + + const pruneViews = () => { + while (viewCache.size > MAX_FILE_VIEW_SESSIONS) { + const first = viewCache.keys().next().value + if (!first) return + const entry = viewCache.get(first) + entry?.dispose() + viewCache.delete(first) + } + } + + const loadView = (dir: string, id: string | undefined) => { + const key = `${dir}:${id ?? WORKSPACE_KEY}` + const existing = viewCache.get(key) + if (existing) { + viewCache.delete(key) + viewCache.set(key, existing) + return existing.value + } + + const entry = createRoot((dispose) => ({ + value: createViewSession(dir, id), + dispose, + })) + + viewCache.set(key, entry) + pruneViews() + return entry.value + } + + const view = createMemo(() => loadView(params.dir!, params.id)) + + function ensure(path: string) { + if (!path) return + if (store.file[path]) return + setStore("file", path, { path, name: getFilename(path) }) + } + + function load(input: string, options?: { force?: boolean }) { + const path = normalize(input) + if (!path) return Promise.resolve() + + ensure(path) + + const current = store.file[path] + if (!options?.force && current?.loaded) return Promise.resolve() + + const pending = inflight.get(path) + if (pending) return pending + + setStore( + "file", + path, + produce((draft) => { + draft.loading = true + draft.error = undefined + }), + ) + + const promise = sdk.client.file + .read({ path }) + .then((x) => { + setStore( + "file", + path, + produce((draft) => { + draft.loaded = true + draft.loading = false + draft.content = x.data + }), + ) + }) + .catch((e) => { + setStore( + "file", + path, + produce((draft) => { + draft.loading = false + draft.error = e.message + }), + ) + showToast({ + variant: "error", + title: language.t("toast.file.loadFailed.title"), + description: e.message, + }) + }) + .finally(() => { + inflight.delete(path) + }) + + inflight.set(path, promise) + return promise + } + + const stop = sdk.event.listen((e) => { + const event = e.details + if (event.type !== "file.watcher.updated") return + const path = normalize(event.properties.file) + if (!path) return + if (path.startsWith(".git/")) return + if (!store.file[path]) return + load(path, { force: true }) + }) + + const get = (input: string) => store.file[normalize(input)] + + const scrollTop = (input: string) => view().scrollTop(normalize(input)) + const scrollLeft = (input: string) => view().scrollLeft(normalize(input)) + const selectedLines = (input: string) => view().selectedLines(normalize(input)) + + const setScrollTop = (input: string, top: number) => { + const path = normalize(input) + view().setScrollTop(path, top) + } + + const setScrollLeft = (input: string, left: number) => { + const path = normalize(input) + view().setScrollLeft(path, left) + } + + const setSelectedLines = (input: string, range: SelectedLineRange | null) => { + const path = normalize(input) + view().setSelectedLines(path, range) + } + + onCleanup(() => { + stop() + disposeViews() + }) + + return { + ready: () => view().ready(), + normalize, + tab, + pathFromTab, + get, + load, + scrollTop, + scrollLeft, + setScrollTop, + setScrollLeft, + selectedLines, + setSelectedLines, + searchFiles: (query: string) => + sdk.client.find.files({ query, dirs: "false" }).then((x) => (x.data ?? []).map(normalize)), + searchFilesAndDirectories: (query: string) => + sdk.client.find.files({ query, dirs: "true" }).then((x) => (x.data ?? []).map(normalize)), + } + }, +}) diff --git a/packages/app/src/context/global-sdk.tsx b/packages/app/src/context/global-sdk.tsx new file mode 100644 index 00000000000..7d93682bf35 --- /dev/null +++ b/packages/app/src/context/global-sdk.tsx @@ -0,0 +1,106 @@ +import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2/client" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { createGlobalEmitter } from "@solid-primitives/event-bus" +import { batch, onCleanup } from "solid-js" +import { usePlatform } from "./platform" +import { useServer } from "./server" + +export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleContext({ + name: "GlobalSDK", + init: () => { + const server = useServer() + const platform = usePlatform() + const abort = new AbortController() + + const eventSdk = createOpencodeClient({ + baseUrl: server.url, + signal: abort.signal, + fetch: platform.fetch, + }) + const emitter = createGlobalEmitter<{ + [key: string]: Event + }>() + + type Queued = { directory: string; payload: Event } + + let queue: Array = [] + const coalesced = new Map() + let timer: ReturnType | undefined + let last = 0 + + const key = (directory: string, payload: Event) => { + if (payload.type === "session.status") return `session.status:${directory}:${payload.properties.sessionID}` + if (payload.type === "lsp.updated") return `lsp.updated:${directory}` + if (payload.type === "message.part.updated") { + const part = payload.properties.part + return `message.part.updated:${directory}:${part.messageID}:${part.id}` + } + } + + const flush = () => { + if (timer) clearTimeout(timer) + timer = undefined + + const events = queue + queue = [] + coalesced.clear() + if (events.length === 0) return + + last = Date.now() + batch(() => { + for (const event of events) { + if (!event) continue + emitter.emit(event.directory, event.payload) + } + }) + } + + const schedule = () => { + if (timer) return + const elapsed = Date.now() - last + timer = setTimeout(flush, Math.max(0, 16 - elapsed)) + } + + const stop = () => { + flush() + } + + void (async () => { + const events = await eventSdk.global.event() + let yielded = Date.now() + for await (const event of events.stream) { + const directory = event.directory ?? "global" + const payload = event.payload + const k = key(directory, payload) + if (k) { + const i = coalesced.get(k) + if (i !== undefined) { + queue[i] = undefined + } + coalesced.set(k, queue.length) + } + queue.push({ directory, payload }) + schedule() + + if (Date.now() - yielded < 8) continue + yielded = Date.now() + await new Promise((resolve) => setTimeout(resolve, 0)) + } + })() + .finally(stop) + .catch(() => undefined) + + onCleanup(() => { + abort.abort() + stop() + }) + + const sdk = createOpencodeClient({ + baseUrl: server.url, + fetch: platform.fetch, + throwOnError: true, + }) + + return { url: server.url, client: sdk, event: emitter } + }, +}) diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx new file mode 100644 index 00000000000..4964ef6e4b1 --- /dev/null +++ b/packages/app/src/context/global-sync.tsx @@ -0,0 +1,773 @@ +import { + type Message, + type Agent, + type Session, + type Part, + type Config, + type Path, + type Project, + type FileDiff, + type Todo, + type SessionStatus, + type ProviderListResponse, + type ProviderAuthResponse, + type Command, + type McpStatus, + type LspStatus, + type VcsInfo, + type PermissionRequest, + type QuestionRequest, + createOpencodeClient, +} from "@opencode-ai/sdk/v2/client" +import { createStore, produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store" +import { Binary } from "@opencode-ai/util/binary" +import { retry } from "@opencode-ai/util/retry" +import { useGlobalSDK } from "./global-sdk" +import { ErrorPage, type InitError } from "../pages/error" +import { + batch, + createContext, + createEffect, + getOwner, + runWithOwner, + useContext, + onCleanup, + onMount, + type Accessor, + type ParentProps, + Switch, + Match, +} from "solid-js" +import { showToast } from "@opencode-ai/ui/toast" +import { getFilename } from "@opencode-ai/util/path" +import { usePlatform } from "./platform" +import { useLanguage } from "@/context/language" +import { Persist, persisted } from "@/utils/persist" + +type State = { + status: "loading" | "partial" | "complete" + agent: Agent[] + command: Command[] + project: string + provider: ProviderListResponse + config: Config + path: Path + session: Session[] + sessionTotal: number + session_status: { + [sessionID: string]: SessionStatus + } + session_diff: { + [sessionID: string]: FileDiff[] + } + todo: { + [sessionID: string]: Todo[] + } + permission: { + [sessionID: string]: PermissionRequest[] + } + question: { + [sessionID: string]: QuestionRequest[] + } + mcp: { + [name: string]: McpStatus + } + lsp: LspStatus[] + vcs: VcsInfo | undefined + limit: number + message: { + [sessionID: string]: Message[] + } + part: { + [messageID: string]: Part[] + } +} + +type VcsCache = { + store: Store<{ value: VcsInfo | undefined }> + setStore: SetStoreFunction<{ value: VcsInfo | undefined }> + ready: Accessor +} + +type ChildOptions = { + bootstrap?: boolean +} + +function createGlobalSync() { + const globalSDK = useGlobalSDK() + const platform = usePlatform() + const language = useLanguage() + const owner = getOwner() + if (!owner) throw new Error("GlobalSync must be created within owner") + const vcsCache = new Map() + const [globalStore, setGlobalStore] = createStore<{ + ready: boolean + error?: InitError + path: Path + project: Project[] + provider: ProviderListResponse + provider_auth: ProviderAuthResponse + config: Config + reload: undefined | "pending" | "complete" + }>({ + ready: false, + path: { state: "", config: "", worktree: "", directory: "", home: "" }, + project: [], + provider: { all: [], connected: [], default: {} }, + provider_auth: {}, + config: {}, + reload: undefined, + }) + let bootstrapQueue: string[] = [] + + createEffect(async () => { + if (globalStore.reload !== "complete") return + if (bootstrapQueue.length) { + for (const directory of bootstrapQueue) { + bootstrapInstance(directory) + } + bootstrap() + } + bootstrapQueue = [] + setGlobalStore("reload", undefined) + }) + + const children: Record, SetStoreFunction]> = {} + const booting = new Map>() + const sessionLoads = new Map>() + const sessionMeta = new Map() + + function ensureChild(directory: string) { + if (!directory) console.error("No directory provided") + if (!children[directory]) { + const cache = runWithOwner(owner, () => + persisted( + Persist.workspace(directory, "vcs", ["vcs.v1"]), + createStore({ value: undefined as VcsInfo | undefined }), + ), + ) + if (!cache) throw new Error("Failed to create persisted cache") + vcsCache.set(directory, { store: cache[0], setStore: cache[1], ready: cache[3] }) + + const init = () => { + children[directory] = createStore({ + project: "", + provider: { all: [], connected: [], default: {} }, + config: {}, + path: { state: "", config: "", worktree: "", directory: "", home: "" }, + status: "loading" as const, + agent: [], + command: [], + session: [], + sessionTotal: 0, + session_status: {}, + session_diff: {}, + todo: {}, + permission: {}, + question: {}, + mcp: {}, + lsp: [], + vcs: cache[0].value, + limit: 5, + message: {}, + part: {}, + }) + } + + runWithOwner(owner, init) + } + const childStore = children[directory] + if (!childStore) throw new Error("Failed to create store") + return childStore + } + + function child(directory: string, options: ChildOptions = {}) { + const childStore = ensureChild(directory) + const shouldBootstrap = options.bootstrap ?? true + if (shouldBootstrap && childStore[0].status === "loading") { + void bootstrapInstance(directory) + } + return childStore + } + + async function loadSessions(directory: string) { + const pending = sessionLoads.get(directory) + if (pending) return pending + + const [store, setStore] = child(directory, { bootstrap: false }) + const meta = sessionMeta.get(directory) + if (meta && meta.limit >= store.limit) return + + const promise = globalSDK.client.session + .list({ directory, roots: true }) + .then((x) => { + const nonArchived = (x.data ?? []) + .filter((s) => !!s?.id) + .filter((s) => !s.time?.archived) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + + // Read the current limit at resolve-time so callers that bump the limit while + // a request is in-flight still get the expanded result. + const limit = store.limit + + const sandboxWorkspace = globalStore.project.some((p) => (p.sandboxes ?? []).includes(directory)) + if (sandboxWorkspace) { + setStore("sessionTotal", nonArchived.length) + setStore("session", reconcile(nonArchived, { key: "id" })) + sessionMeta.set(directory, { limit }) + return + } + + const fourHoursAgo = Date.now() - 4 * 60 * 60 * 1000 + // Include up to the limit, plus any updated in the last 4 hours + const sessions = nonArchived.filter((s, i) => { + if (i < limit) return true + const updated = new Date(s.time?.updated ?? s.time?.created).getTime() + return updated > fourHoursAgo + }) + // Store total session count (used for "load more" pagination) + setStore("sessionTotal", nonArchived.length) + setStore("session", reconcile(sessions, { key: "id" })) + sessionMeta.set(directory, { limit }) + }) + .catch((err) => { + console.error("Failed to load sessions", err) + const project = getFilename(directory) + showToast({ title: language.t("toast.session.listFailed.title", { project }), description: err.message }) + }) + + sessionLoads.set(directory, promise) + promise.finally(() => { + sessionLoads.delete(directory) + }) + return promise + } + + async function bootstrapInstance(directory: string) { + if (!directory) return + const pending = booting.get(directory) + if (pending) return pending + + const promise = (async () => { + const [store, setStore] = ensureChild(directory) + const cache = vcsCache.get(directory) + if (!cache) return + const sdk = createOpencodeClient({ + baseUrl: globalSDK.url, + fetch: platform.fetch, + directory, + throwOnError: true, + }) + + setStore("status", "loading") + + createEffect(() => { + if (!cache.ready()) return + const cached = cache.store.value + if (!cached?.branch) return + setStore("vcs", (value) => value ?? cached) + }) + + const blockingRequests = { + project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)), + provider: () => + sdk.provider.list().then((x) => { + const data = x.data! + setStore("provider", { + ...data, + all: data.all.map((provider) => ({ + ...provider, + models: Object.fromEntries( + Object.entries(provider.models).filter(([, info]) => info.status !== "deprecated"), + ), + })), + }) + }), + agent: () => sdk.app.agents().then((x) => setStore("agent", x.data ?? [])), + config: () => sdk.config.get().then((x) => setStore("config", x.data!)), + } + + try { + await Promise.all(Object.values(blockingRequests).map((p) => retry(p))) + } catch (err) { + console.error("Failed to bootstrap instance", err) + const project = getFilename(directory) + const message = err instanceof Error ? err.message : String(err) + showToast({ title: `Failed to reload ${project}`, description: message }) + setStore("status", "partial") + return + } + + if (store.status !== "complete") setStore("status", "partial") + + Promise.all([ + sdk.path.get().then((x) => setStore("path", x.data!)), + sdk.command.list().then((x) => setStore("command", x.data ?? [])), + sdk.session.status().then((x) => setStore("session_status", x.data!)), + loadSessions(directory), + sdk.mcp.status().then((x) => setStore("mcp", x.data!)), + sdk.lsp.status().then((x) => setStore("lsp", x.data!)), + sdk.vcs.get().then((x) => { + const next = x.data ?? store.vcs + setStore("vcs", next) + if (next?.branch) cache.setStore("value", next) + }), + sdk.permission.list().then((x) => { + const grouped: Record = {} + for (const perm of x.data ?? []) { + if (!perm?.id || !perm.sessionID) continue + const existing = grouped[perm.sessionID] + if (existing) { + existing.push(perm) + continue + } + grouped[perm.sessionID] = [perm] + } + + batch(() => { + for (const sessionID of Object.keys(store.permission)) { + if (grouped[sessionID]) continue + setStore("permission", sessionID, []) + } + for (const [sessionID, permissions] of Object.entries(grouped)) { + setStore( + "permission", + sessionID, + reconcile( + permissions + .filter((p) => !!p?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)), + { key: "id" }, + ), + ) + } + }) + }), + sdk.question.list().then((x) => { + const grouped: Record = {} + for (const question of x.data ?? []) { + if (!question?.id || !question.sessionID) continue + const existing = grouped[question.sessionID] + if (existing) { + existing.push(question) + continue + } + grouped[question.sessionID] = [question] + } + + batch(() => { + for (const sessionID of Object.keys(store.question)) { + if (grouped[sessionID]) continue + setStore("question", sessionID, []) + } + for (const [sessionID, questions] of Object.entries(grouped)) { + setStore( + "question", + sessionID, + reconcile( + questions + .filter((q) => !!q?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)), + { key: "id" }, + ), + ) + } + }) + }), + ]).then(() => { + setStore("status", "complete") + }) + })() + + booting.set(directory, promise) + promise.finally(() => { + booting.delete(directory) + }) + return promise + } + + const unsub = globalSDK.event.listen((e) => { + const directory = e.name + const event = e.details + + if (directory === "global") { + switch (event?.type) { + case "global.disposed": { + if (globalStore.reload) return + bootstrap() + break + } + case "project.updated": { + const result = Binary.search(globalStore.project, event.properties.id, (s) => s.id) + if (result.found) { + setGlobalStore("project", result.index, reconcile(event.properties)) + return + } + setGlobalStore( + "project", + produce((draft) => { + draft.splice(result.index, 0, event.properties) + }), + ) + break + } + } + return + } + + const existing = children[directory] + if (!existing) return + + const [store, setStore] = existing + switch (event.type) { + case "server.instance.disposed": { + if (globalStore.reload) { + bootstrapQueue.push(directory) + return + } + bootstrapInstance(directory) + break + } + case "session.created": { + const result = Binary.search(store.session, event.properties.info.id, (s) => s.id) + if (result.found) { + setStore("session", result.index, reconcile(event.properties.info)) + break + } + setStore( + "session", + produce((draft) => { + draft.splice(result.index, 0, event.properties.info) + }), + ) + if (!event.properties.info.parentID) { + setStore("sessionTotal", store.sessionTotal + 1) + } + break + } + case "session.updated": { + const result = Binary.search(store.session, event.properties.info.id, (s) => s.id) + if (event.properties.info.time.archived) { + if (result.found) { + setStore( + "session", + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + } + if (event.properties.info.parentID) break + setStore("sessionTotal", (value) => Math.max(0, value - 1)) + break + } + if (result.found) { + setStore("session", result.index, reconcile(event.properties.info)) + break + } + setStore( + "session", + produce((draft) => { + draft.splice(result.index, 0, event.properties.info) + }), + ) + break + } + case "session.deleted": { + const result = Binary.search(store.session, event.properties.info.id, (s) => s.id) + if (result.found) { + setStore( + "session", + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + } + if (event.properties.info.parentID) break + setStore("sessionTotal", (value) => Math.max(0, value - 1)) + break + } + case "session.diff": + setStore("session_diff", event.properties.sessionID, reconcile(event.properties.diff, { key: "file" })) + break + case "todo.updated": + setStore("todo", event.properties.sessionID, reconcile(event.properties.todos, { key: "id" })) + break + case "session.status": { + setStore("session_status", event.properties.sessionID, reconcile(event.properties.status)) + break + } + case "message.updated": { + const messages = store.message[event.properties.info.sessionID] + if (!messages) { + setStore("message", event.properties.info.sessionID, [event.properties.info]) + break + } + const result = Binary.search(messages, event.properties.info.id, (m) => m.id) + if (result.found) { + setStore("message", event.properties.info.sessionID, result.index, reconcile(event.properties.info)) + break + } + setStore( + "message", + event.properties.info.sessionID, + produce((draft) => { + draft.splice(result.index, 0, event.properties.info) + }), + ) + break + } + case "message.removed": { + const messages = store.message[event.properties.sessionID] + if (!messages) break + const result = Binary.search(messages, event.properties.messageID, (m) => m.id) + if (result.found) { + setStore( + "message", + event.properties.sessionID, + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + } + break + } + case "message.part.updated": { + const part = event.properties.part + const parts = store.part[part.messageID] + if (!parts) { + setStore("part", part.messageID, [part]) + break + } + const result = Binary.search(parts, part.id, (p) => p.id) + if (result.found) { + setStore("part", part.messageID, result.index, reconcile(part)) + break + } + setStore( + "part", + part.messageID, + produce((draft) => { + draft.splice(result.index, 0, part) + }), + ) + break + } + case "message.part.removed": { + const parts = store.part[event.properties.messageID] + if (!parts) break + const result = Binary.search(parts, event.properties.partID, (p) => p.id) + if (result.found) { + setStore( + "part", + event.properties.messageID, + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + } + break + } + case "vcs.branch.updated": { + const next = { branch: event.properties.branch } + setStore("vcs", next) + const cache = vcsCache.get(directory) + if (cache) cache.setStore("value", next) + break + } + case "permission.asked": { + const sessionID = event.properties.sessionID + const permissions = store.permission[sessionID] + if (!permissions) { + setStore("permission", sessionID, [event.properties]) + break + } + + const result = Binary.search(permissions, event.properties.id, (p) => p.id) + if (result.found) { + setStore("permission", sessionID, result.index, reconcile(event.properties)) + break + } + + setStore( + "permission", + sessionID, + produce((draft) => { + draft.splice(result.index, 0, event.properties) + }), + ) + break + } + case "permission.replied": { + const permissions = store.permission[event.properties.sessionID] + if (!permissions) break + const result = Binary.search(permissions, event.properties.requestID, (p) => p.id) + if (!result.found) break + setStore( + "permission", + event.properties.sessionID, + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + break + } + case "question.asked": { + const sessionID = event.properties.sessionID + const questions = store.question[sessionID] + if (!questions) { + setStore("question", sessionID, [event.properties]) + break + } + + const result = Binary.search(questions, event.properties.id, (q) => q.id) + if (result.found) { + setStore("question", sessionID, result.index, reconcile(event.properties)) + break + } + + setStore( + "question", + sessionID, + produce((draft) => { + draft.splice(result.index, 0, event.properties) + }), + ) + break + } + case "question.replied": + case "question.rejected": { + const questions = store.question[event.properties.sessionID] + if (!questions) break + const result = Binary.search(questions, event.properties.requestID, (q) => q.id) + if (!result.found) break + setStore( + "question", + event.properties.sessionID, + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + break + } + case "lsp.updated": { + const sdk = createOpencodeClient({ + baseUrl: globalSDK.url, + fetch: platform.fetch, + directory, + throwOnError: true, + }) + sdk.lsp.status().then((x) => setStore("lsp", x.data ?? [])) + break + } + } + }) + onCleanup(unsub) + + async function bootstrap() { + const health = await globalSDK.client.global + .health() + .then((x) => x.data) + .catch(() => undefined) + if (!health?.healthy) { + setGlobalStore("error", new Error(language.t("error.globalSync.connectFailed", { url: globalSDK.url }))) + return + } + + return Promise.all([ + retry(() => + globalSDK.client.path.get().then((x) => { + setGlobalStore("path", x.data!) + }), + ), + retry(() => + globalSDK.client.config.get().then((x) => { + setGlobalStore("config", x.data!) + }), + ), + retry(() => + globalSDK.client.project.list().then(async (x) => { + const projects = (x.data ?? []) + .filter((p) => !!p?.id) + .filter((p) => !!p.worktree && !p.worktree.includes("opencode-test")) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + setGlobalStore("project", projects) + }), + ), + retry(() => + globalSDK.client.provider.list().then((x) => { + const data = x.data! + setGlobalStore("provider", { + ...data, + all: data.all.map((provider) => ({ + ...provider, + models: Object.fromEntries( + Object.entries(provider.models).filter(([, info]) => info.status !== "deprecated"), + ), + })), + }) + }), + ), + retry(() => + globalSDK.client.provider.auth().then((x) => { + setGlobalStore("provider_auth", x.data ?? {}) + }), + ), + ]) + .then(() => setGlobalStore("ready", true)) + .catch((e) => setGlobalStore("error", e)) + } + + onMount(() => { + bootstrap() + }) + + return { + data: globalStore, + set: setGlobalStore, + get ready() { + return globalStore.ready + }, + get error() { + return globalStore.error + }, + child, + bootstrap, + updateConfig: async (config: Config) => { + setGlobalStore("reload", "pending") + const response = await globalSDK.client.config.update({ config }) + setTimeout(() => { + setGlobalStore("reload", "complete") + }, 1000) + return response + }, + project: { + loadSessions, + }, + } +} + +const GlobalSyncContext = createContext>() + +export function GlobalSyncProvider(props: ParentProps) { + const value = createGlobalSync() + return ( + + + + + + {props.children} + + + ) +} + +export function useGlobalSync() { + const context = useContext(GlobalSyncContext) + if (!context) throw new Error("useGlobalSync must be used within GlobalSyncProvider") + return context +} diff --git a/packages/app/src/context/language.tsx b/packages/app/src/context/language.tsx new file mode 100644 index 00000000000..da10e4773ae --- /dev/null +++ b/packages/app/src/context/language.tsx @@ -0,0 +1,161 @@ +import * as i18n from "@solid-primitives/i18n" +import { createEffect, createMemo } from "solid-js" +import { createStore } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { Persist, persisted } from "@/utils/persist" +import { dict as en } from "@/i18n/en" +import { dict as zh } from "@/i18n/zh" +import { dict as zht } from "@/i18n/zht" +import { dict as ko } from "@/i18n/ko" +import { dict as de } from "@/i18n/de" +import { dict as es } from "@/i18n/es" +import { dict as fr } from "@/i18n/fr" +import { dict as da } from "@/i18n/da" +import { dict as ja } from "@/i18n/ja" +import { dict as pl } from "@/i18n/pl" +import { dict as ru } from "@/i18n/ru" +import { dict as ar } from "@/i18n/ar" +import { dict as no } from "@/i18n/no" +import { dict as br } from "@/i18n/br" +import { dict as uiEn } from "@opencode-ai/ui/i18n/en" +import { dict as uiZh } from "@opencode-ai/ui/i18n/zh" +import { dict as uiZht } from "@opencode-ai/ui/i18n/zht" +import { dict as uiKo } from "@opencode-ai/ui/i18n/ko" +import { dict as uiDe } from "@opencode-ai/ui/i18n/de" +import { dict as uiEs } from "@opencode-ai/ui/i18n/es" +import { dict as uiFr } from "@opencode-ai/ui/i18n/fr" +import { dict as uiDa } from "@opencode-ai/ui/i18n/da" +import { dict as uiJa } from "@opencode-ai/ui/i18n/ja" +import { dict as uiPl } from "@opencode-ai/ui/i18n/pl" +import { dict as uiRu } from "@opencode-ai/ui/i18n/ru" +import { dict as uiAr } from "@opencode-ai/ui/i18n/ar" +import { dict as uiNo } from "@opencode-ai/ui/i18n/no" +import { dict as uiBr } from "@opencode-ai/ui/i18n/br" + +export type Locale = "en" | "zh" | "zht" | "ko" | "de" | "es" | "fr" | "da" | "ja" | "pl" | "ru" | "ar" | "no" | "br" + +type RawDictionary = typeof en & typeof uiEn +type Dictionary = i18n.Flatten + +const LOCALES: readonly Locale[] = ["en", "zh", "zht", "ko", "de", "es", "fr", "da", "ja", "pl", "ru", "ar", "no", "br"] + +function detectLocale(): Locale { + if (typeof navigator !== "object") return "en" + + const languages = navigator.languages?.length ? navigator.languages : [navigator.language] + for (const language of languages) { + if (!language) continue + if (language.toLowerCase().startsWith("zh")) { + if (language.toLowerCase().includes("hant")) return "zht" + return "zh" + } + if (language.toLowerCase().startsWith("ko")) return "ko" + if (language.toLowerCase().startsWith("de")) return "de" + if (language.toLowerCase().startsWith("es")) return "es" + if (language.toLowerCase().startsWith("fr")) return "fr" + if (language.toLowerCase().startsWith("da")) return "da" + if (language.toLowerCase().startsWith("ja")) return "ja" + if (language.toLowerCase().startsWith("pl")) return "pl" + if (language.toLowerCase().startsWith("ru")) return "ru" + if (language.toLowerCase().startsWith("ar")) return "ar" + if ( + language.toLowerCase().startsWith("no") || + language.toLowerCase().startsWith("nb") || + language.toLowerCase().startsWith("nn") + ) + return "no" + if (language.toLowerCase().startsWith("pt")) return "br" + } + + return "en" +} + +export const { use: useLanguage, provider: LanguageProvider } = createSimpleContext({ + name: "Language", + init: () => { + const [store, setStore, _, ready] = persisted( + Persist.global("language", ["language.v1"]), + createStore({ + locale: detectLocale() as Locale, + }), + ) + + const locale = createMemo(() => { + if (store.locale === "zh") return "zh" + if (store.locale === "zht") return "zht" + if (store.locale === "ko") return "ko" + if (store.locale === "de") return "de" + if (store.locale === "es") return "es" + if (store.locale === "fr") return "fr" + if (store.locale === "da") return "da" + if (store.locale === "ja") return "ja" + if (store.locale === "pl") return "pl" + if (store.locale === "ru") return "ru" + if (store.locale === "ar") return "ar" + if (store.locale === "no") return "no" + if (store.locale === "br") return "br" + return "en" + }) + + createEffect(() => { + const current = locale() + if (store.locale === current) return + setStore("locale", current) + }) + + const base = i18n.flatten({ ...en, ...uiEn }) + const dict = createMemo(() => { + if (locale() === "en") return base + if (locale() === "zh") return { ...base, ...i18n.flatten({ ...zh, ...uiZh }) } + if (locale() === "zht") return { ...base, ...i18n.flatten({ ...zht, ...uiZht }) } + if (locale() === "de") return { ...base, ...i18n.flatten({ ...de, ...uiDe }) } + if (locale() === "es") return { ...base, ...i18n.flatten({ ...es, ...uiEs }) } + if (locale() === "fr") return { ...base, ...i18n.flatten({ ...fr, ...uiFr }) } + if (locale() === "da") return { ...base, ...i18n.flatten({ ...da, ...uiDa }) } + if (locale() === "ja") return { ...base, ...i18n.flatten({ ...ja, ...uiJa }) } + if (locale() === "pl") return { ...base, ...i18n.flatten({ ...pl, ...uiPl }) } + if (locale() === "ru") return { ...base, ...i18n.flatten({ ...ru, ...uiRu }) } + if (locale() === "ar") return { ...base, ...i18n.flatten({ ...ar, ...uiAr }) } + if (locale() === "no") return { ...base, ...i18n.flatten({ ...no, ...uiNo }) } + if (locale() === "br") return { ...base, ...i18n.flatten({ ...br, ...uiBr }) } + return { ...base, ...i18n.flatten({ ...ko, ...uiKo }) } + }) + + const t = i18n.translator(dict, i18n.resolveTemplate) + + const labelKey: Record = { + en: "language.en", + zh: "language.zh", + zht: "language.zht", + ko: "language.ko", + de: "language.de", + es: "language.es", + fr: "language.fr", + da: "language.da", + ja: "language.ja", + pl: "language.pl", + ru: "language.ru", + ar: "language.ar", + no: "language.no", + br: "language.br", + } + + const label = (value: Locale) => t(labelKey[value]) + + createEffect(() => { + if (typeof document !== "object") return + document.documentElement.lang = locale() + }) + + return { + ready, + locale, + locales: LOCALES, + label, + t, + setLocale(next: Locale) { + setStore("locale", next) + }, + } + }, +}) diff --git a/packages/app/src/context/layout-scroll.test.ts b/packages/app/src/context/layout-scroll.test.ts new file mode 100644 index 00000000000..b7962c411cd --- /dev/null +++ b/packages/app/src/context/layout-scroll.test.ts @@ -0,0 +1,73 @@ +import { describe, expect, test } from "bun:test" +import { createRoot } from "solid-js" +import { createStore } from "solid-js/store" +import { makePersisted, type SyncStorage } from "@solid-primitives/storage" +import { createScrollPersistence } from "./layout-scroll" + +describe("createScrollPersistence", () => { + test("debounces persisted scroll writes", async () => { + const key = "layout-scroll.test" + const data = new Map() + const writes: string[] = [] + const stats = { flushes: 0 } + + const storage = { + getItem: (k: string) => data.get(k) ?? null, + setItem: (k: string, v: string) => { + data.set(k, v) + if (k === key) writes.push(v) + }, + removeItem: (k: string) => { + data.delete(k) + }, + } as SyncStorage + + await new Promise((resolve, reject) => { + createRoot((dispose) => { + const [raw, setRaw] = createStore({ + sessionView: {} as Record }>, + }) + + const [store, setStore] = makePersisted([raw, setRaw], { name: key, storage }) + + const scroll = createScrollPersistence({ + debounceMs: 30, + getSnapshot: (sessionKey) => store.sessionView[sessionKey]?.scroll, + onFlush: (sessionKey, next) => { + stats.flushes += 1 + + const current = store.sessionView[sessionKey] + if (!current) { + setStore("sessionView", sessionKey, { scroll: next }) + return + } + setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...(prev ?? {}), ...next })) + }, + }) + + const run = async () => { + await new Promise((r) => setTimeout(r, 0)) + writes.length = 0 + + for (const i of Array.from({ length: 100 }, (_, n) => n)) { + scroll.setScroll("session", "review", { x: 0, y: i }) + } + + await new Promise((r) => setTimeout(r, 120)) + + expect(stats.flushes).toBeGreaterThanOrEqual(1) + expect(writes.length).toBeGreaterThanOrEqual(1) + expect(writes.length).toBeLessThanOrEqual(2) + } + + void run() + .then(resolve) + .catch(reject) + .finally(() => { + scroll.dispose() + dispose() + }) + }) + }) + }) +}) diff --git a/packages/app/src/context/layout-scroll.ts b/packages/app/src/context/layout-scroll.ts new file mode 100644 index 00000000000..30b0f69044a --- /dev/null +++ b/packages/app/src/context/layout-scroll.ts @@ -0,0 +1,118 @@ +import { createStore, produce } from "solid-js/store" + +export type SessionScroll = { + x: number + y: number +} + +type ScrollMap = Record + +type Options = { + debounceMs?: number + getSnapshot: (sessionKey: string) => ScrollMap | undefined + onFlush: (sessionKey: string, scroll: ScrollMap) => void +} + +export function createScrollPersistence(opts: Options) { + const wait = opts.debounceMs ?? 200 + const [cache, setCache] = createStore>({}) + const dirty = new Set() + const timers = new Map>() + + function clone(input?: ScrollMap) { + const out: ScrollMap = {} + if (!input) return out + + for (const key of Object.keys(input)) { + const pos = input[key] + if (!pos) continue + out[key] = { x: pos.x, y: pos.y } + } + + return out + } + + function seed(sessionKey: string) { + if (cache[sessionKey]) return + setCache(sessionKey, clone(opts.getSnapshot(sessionKey))) + } + + function scroll(sessionKey: string, tab: string) { + seed(sessionKey) + return cache[sessionKey]?.[tab] ?? opts.getSnapshot(sessionKey)?.[tab] + } + + function schedule(sessionKey: string) { + const prev = timers.get(sessionKey) + if (prev) clearTimeout(prev) + timers.set( + sessionKey, + setTimeout(() => flush(sessionKey), wait), + ) + } + + function setScroll(sessionKey: string, tab: string, pos: SessionScroll) { + seed(sessionKey) + + const prev = cache[sessionKey]?.[tab] + if (prev?.x === pos.x && prev?.y === pos.y) return + + setCache(sessionKey, tab, { x: pos.x, y: pos.y }) + dirty.add(sessionKey) + schedule(sessionKey) + } + + function flush(sessionKey: string) { + const timer = timers.get(sessionKey) + if (timer) clearTimeout(timer) + timers.delete(sessionKey) + + if (!dirty.has(sessionKey)) return + dirty.delete(sessionKey) + + opts.onFlush(sessionKey, clone(cache[sessionKey])) + } + + function flushAll() { + const keys = Array.from(dirty) + if (keys.length === 0) return + + for (const key of keys) { + flush(key) + } + } + + function drop(keys: string[]) { + if (keys.length === 0) return + + for (const key of keys) { + const timer = timers.get(key) + if (timer) clearTimeout(timer) + timers.delete(key) + dirty.delete(key) + } + + setCache( + produce((draft) => { + for (const key of keys) { + delete draft[key] + } + }), + ) + } + + function dispose() { + drop(Array.from(timers.keys())) + } + + return { + cache, + drop, + flush, + flushAll, + scroll, + seed, + setScroll, + dispose, + } +} diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx new file mode 100644 index 00000000000..7a355629059 --- /dev/null +++ b/packages/app/src/context/layout.tsx @@ -0,0 +1,570 @@ +import { createStore, produce } from "solid-js/store" +import { batch, createEffect, createMemo, onCleanup, onMount } from "solid-js" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { useGlobalSync } from "./global-sync" +import { useGlobalSDK } from "./global-sdk" +import { useServer } from "./server" +import { Project } from "@opencode-ai/sdk/v2" +import { Persist, persisted, removePersisted } from "@/utils/persist" +import { same } from "@/utils/same" +import { createScrollPersistence, type SessionScroll } from "./layout-scroll" + +const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const +export type AvatarColorKey = (typeof AVATAR_COLOR_KEYS)[number] + +export function getAvatarColors(key?: string) { + if (key && AVATAR_COLOR_KEYS.includes(key as AvatarColorKey)) { + return { + background: `var(--avatar-background-${key})`, + foreground: `var(--avatar-text-${key})`, + } + } + return { + background: "var(--surface-info-base)", + foreground: "var(--text-base)", + } +} + +type SessionTabs = { + active?: string + all: string[] +} + +type SessionView = { + scroll: Record + reviewOpen?: string[] +} + +export type LocalProject = Partial & { worktree: string; expanded: boolean } + +export type ReviewDiffStyle = "unified" | "split" + +export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({ + name: "Layout", + init: () => { + const globalSdk = useGlobalSDK() + const globalSync = useGlobalSync() + const server = useServer() + + const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value) + + const migrate = (value: unknown) => { + if (!isRecord(value)) return value + const sidebar = value.sidebar + if (!isRecord(sidebar)) return value + if (typeof sidebar.workspaces !== "boolean") return value + return { + ...value, + sidebar: { + ...sidebar, + workspaces: {}, + workspacesDefault: sidebar.workspaces, + }, + } + } + + const target = Persist.global("layout", ["layout.v6"]) + const [store, setStore, _, ready] = persisted( + { ...target, migrate }, + createStore({ + sidebar: { + opened: false, + width: 344, + workspaces: {} as Record, + workspacesDefault: false, + }, + terminal: { + height: 280, + opened: false, + }, + review: { + diffStyle: "split" as ReviewDiffStyle, + panelOpened: true, + }, + session: { + width: 600, + }, + mobileSidebar: { + opened: false, + }, + sessionTabs: {} as Record, + sessionView: {} as Record, + }), + ) + + const MAX_SESSION_KEYS = 50 + const meta = { active: undefined as string | undefined, pruned: false } + const used = new Map() + + const SESSION_STATE_KEYS = [ + { key: "prompt", legacy: "prompt", version: "v2" }, + { key: "terminal", legacy: "terminal", version: "v1" }, + { key: "file-view", legacy: "file", version: "v1" }, + ] as const + + const dropSessionState = (keys: string[]) => { + for (const key of keys) { + const parts = key.split("/") + const dir = parts[0] + const session = parts[1] + if (!dir) continue + + for (const entry of SESSION_STATE_KEYS) { + const target = session ? Persist.session(dir, session, entry.key) : Persist.workspace(dir, entry.key) + void removePersisted(target) + + const legacyKey = `${dir}/${entry.legacy}${session ? "/" + session : ""}.${entry.version}` + void removePersisted({ key: legacyKey }) + } + } + } + + function prune(keep?: string) { + if (!keep) return + + const keys = new Set() + for (const key of Object.keys(store.sessionView)) keys.add(key) + for (const key of Object.keys(store.sessionTabs)) keys.add(key) + if (keys.size <= MAX_SESSION_KEYS) return + + const score = (key: string) => { + if (key === keep) return Number.MAX_SAFE_INTEGER + return used.get(key) ?? 0 + } + + const ordered = Array.from(keys).sort((a, b) => score(b) - score(a)) + const drop = ordered.slice(MAX_SESSION_KEYS) + if (drop.length === 0) return + + setStore( + produce((draft) => { + for (const key of drop) { + delete draft.sessionView[key] + delete draft.sessionTabs[key] + } + }), + ) + + scroll.drop(drop) + dropSessionState(drop) + + for (const key of drop) { + used.delete(key) + } + } + + function touch(sessionKey: string) { + meta.active = sessionKey + used.set(sessionKey, Date.now()) + + if (!ready()) return + if (meta.pruned) return + + meta.pruned = true + prune(sessionKey) + } + + const scroll = createScrollPersistence({ + debounceMs: 250, + getSnapshot: (sessionKey) => store.sessionView[sessionKey]?.scroll, + onFlush: (sessionKey, next) => { + const current = store.sessionView[sessionKey] + const keep = meta.active ?? sessionKey + if (!current) { + setStore("sessionView", sessionKey, { scroll: next }) + prune(keep) + return + } + + setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...(prev ?? {}), ...next })) + prune(keep) + }, + }) + + createEffect(() => { + if (!ready()) return + if (meta.pruned) return + const active = meta.active + if (!active) return + meta.pruned = true + prune(active) + }) + + onMount(() => { + const flush = () => batch(() => scroll.flushAll()) + const handleVisibility = () => { + if (document.visibilityState !== "hidden") return + flush() + } + + window.addEventListener("pagehide", flush) + document.addEventListener("visibilitychange", handleVisibility) + + onCleanup(() => { + window.removeEventListener("pagehide", flush) + document.removeEventListener("visibilitychange", handleVisibility) + scroll.dispose() + }) + }) + + const [colors, setColors] = createStore>({}) + + function pickAvailableColor(used: Set): AvatarColorKey { + const available = AVATAR_COLOR_KEYS.filter((c) => !used.has(c)) + if (available.length === 0) return AVATAR_COLOR_KEYS[Math.floor(Math.random() * AVATAR_COLOR_KEYS.length)] + return available[Math.floor(Math.random() * available.length)] + } + + function enrich(project: { worktree: string; expanded: boolean }) { + const [childStore] = globalSync.child(project.worktree) + const projectID = childStore.project + const metadata = projectID + ? globalSync.data.project.find((x) => x.id === projectID) + : globalSync.data.project.find((x) => x.worktree === project.worktree) + return { + ...(metadata ?? {}), + ...project, + icon: { + url: metadata?.icon?.url, + override: metadata?.icon?.override, + color: metadata?.icon?.color, + }, + } + } + + const roots = createMemo(() => { + const map = new Map() + for (const project of globalSync.data.project) { + const sandboxes = project.sandboxes ?? [] + for (const sandbox of sandboxes) { + map.set(sandbox, project.worktree) + } + } + return map + }) + + createEffect(() => { + const map = roots() + if (map.size === 0) return + + const projects = server.projects.list() + const seen = new Set(projects.map((project) => project.worktree)) + + batch(() => { + for (const project of projects) { + const root = map.get(project.worktree) + if (!root) continue + + server.projects.close(project.worktree) + + if (!seen.has(root)) { + server.projects.open(root) + seen.add(root) + } + + if (project.expanded) server.projects.expand(root) + } + }) + }) + + const enriched = createMemo(() => server.projects.list().map(enrich)) + const list = createMemo(() => { + const projects = enriched() + return projects.map((project) => { + const color = project.icon?.color ?? colors[project.worktree] + if (!color) return project + const icon = project.icon ? { ...project.icon, color } : { color } + return { ...project, icon } + }) + }) + + createEffect(() => { + const projects = enriched() + if (projects.length === 0) return + + const used = new Set() + for (const project of projects) { + const color = project.icon?.color ?? colors[project.worktree] + if (color) used.add(color) + } + + for (const project of projects) { + if (project.icon?.color) continue + if (colors[project.worktree]) continue + const color = pickAvailableColor(used) + used.add(color) + setColors(project.worktree, color) + if (!project.id) continue + void globalSdk.client.project.update({ projectID: project.id, directory: project.worktree, icon: { color } }) + } + }) + + onMount(() => { + Promise.all( + server.projects.list().map((project) => { + return globalSync.project.loadSessions(project.worktree) + }), + ) + }) + + return { + ready, + projects: { + list, + open(directory: string) { + const root = roots().get(directory) ?? directory + if (server.projects.list().find((x) => x.worktree === root)) return + globalSync.project.loadSessions(root) + server.projects.open(root) + }, + close(directory: string) { + server.projects.close(directory) + }, + expand(directory: string) { + server.projects.expand(directory) + }, + collapse(directory: string) { + server.projects.collapse(directory) + }, + move(directory: string, toIndex: number) { + server.projects.move(directory, toIndex) + }, + }, + sidebar: { + opened: createMemo(() => store.sidebar.opened), + open() { + setStore("sidebar", "opened", true) + }, + close() { + setStore("sidebar", "opened", false) + }, + toggle() { + setStore("sidebar", "opened", (x) => !x) + }, + width: createMemo(() => store.sidebar.width), + resize(width: number) { + setStore("sidebar", "width", width) + }, + workspaces(directory: string) { + return createMemo(() => store.sidebar.workspaces[directory] ?? store.sidebar.workspacesDefault ?? false) + }, + setWorkspaces(directory: string, value: boolean) { + setStore("sidebar", "workspaces", directory, value) + }, + toggleWorkspaces(directory: string) { + const current = store.sidebar.workspaces[directory] ?? store.sidebar.workspacesDefault ?? false + setStore("sidebar", "workspaces", directory, !current) + }, + }, + terminal: { + height: createMemo(() => store.terminal.height), + resize(height: number) { + setStore("terminal", "height", height) + }, + }, + review: { + diffStyle: createMemo(() => store.review?.diffStyle ?? "split"), + setDiffStyle(diffStyle: ReviewDiffStyle) { + if (!store.review) { + setStore("review", { diffStyle }) + return + } + setStore("review", "diffStyle", diffStyle) + }, + }, + session: { + width: createMemo(() => store.session?.width ?? 600), + resize(width: number) { + if (!store.session) { + setStore("session", { width }) + return + } + setStore("session", "width", width) + }, + }, + mobileSidebar: { + opened: createMemo(() => store.mobileSidebar?.opened ?? false), + show() { + setStore("mobileSidebar", "opened", true) + }, + hide() { + setStore("mobileSidebar", "opened", false) + }, + toggle() { + setStore("mobileSidebar", "opened", (x) => !x) + }, + }, + view(sessionKey: string) { + touch(sessionKey) + scroll.seed(sessionKey) + const s = createMemo(() => store.sessionView[sessionKey] ?? { scroll: {} }) + const terminalOpened = createMemo(() => store.terminal?.opened ?? false) + const reviewPanelOpened = createMemo(() => store.review?.panelOpened ?? true) + + function setTerminalOpened(next: boolean) { + const current = store.terminal + if (!current) { + setStore("terminal", { height: 280, opened: next }) + return + } + + const value = current.opened ?? false + if (value === next) return + setStore("terminal", "opened", next) + } + + function setReviewPanelOpened(next: boolean) { + const current = store.review + if (!current) { + setStore("review", { diffStyle: "split" as ReviewDiffStyle, panelOpened: next }) + return + } + + const value = current.panelOpened ?? true + if (value === next) return + setStore("review", "panelOpened", next) + } + + return { + scroll(tab: string) { + return scroll.scroll(sessionKey, tab) + }, + setScroll(tab: string, pos: SessionScroll) { + scroll.setScroll(sessionKey, tab, pos) + }, + terminal: { + opened: terminalOpened, + open() { + setTerminalOpened(true) + }, + close() { + setTerminalOpened(false) + }, + toggle() { + setTerminalOpened(!terminalOpened()) + }, + }, + reviewPanel: { + opened: reviewPanelOpened, + open() { + setReviewPanelOpened(true) + }, + close() { + setReviewPanelOpened(false) + }, + toggle() { + setReviewPanelOpened(!reviewPanelOpened()) + }, + }, + review: { + open: createMemo(() => s().reviewOpen), + setOpen(open: string[]) { + const current = store.sessionView[sessionKey] + if (!current) { + setStore("sessionView", sessionKey, { + scroll: {}, + reviewOpen: open, + }) + return + } + + if (same(current.reviewOpen, open)) return + setStore("sessionView", sessionKey, "reviewOpen", open) + }, + }, + } + }, + tabs(sessionKey: string) { + touch(sessionKey) + const tabs = createMemo(() => store.sessionTabs[sessionKey] ?? { all: [] }) + return { + tabs, + active: createMemo(() => tabs().active), + all: createMemo(() => tabs().all), + setActive(tab: string | undefined) { + if (!store.sessionTabs[sessionKey]) { + setStore("sessionTabs", sessionKey, { all: [], active: tab }) + } else { + setStore("sessionTabs", sessionKey, "active", tab) + } + }, + setAll(all: string[]) { + if (!store.sessionTabs[sessionKey]) { + setStore("sessionTabs", sessionKey, { all, active: undefined }) + } else { + setStore("sessionTabs", sessionKey, "all", all) + } + }, + async open(tab: string) { + const current = store.sessionTabs[sessionKey] ?? { all: [] } + + if (tab === "review") { + if (!store.sessionTabs[sessionKey]) { + setStore("sessionTabs", sessionKey, { all: [], active: tab }) + return + } + setStore("sessionTabs", sessionKey, "active", tab) + return + } + + if (tab === "context") { + const all = [tab, ...current.all.filter((x) => x !== tab)] + if (!store.sessionTabs[sessionKey]) { + setStore("sessionTabs", sessionKey, { all, active: tab }) + return + } + setStore("sessionTabs", sessionKey, "all", all) + setStore("sessionTabs", sessionKey, "active", tab) + return + } + + if (!current.all.includes(tab)) { + if (!store.sessionTabs[sessionKey]) { + setStore("sessionTabs", sessionKey, { all: [tab], active: tab }) + return + } + setStore("sessionTabs", sessionKey, "all", [...current.all, tab]) + setStore("sessionTabs", sessionKey, "active", tab) + return + } + + if (!store.sessionTabs[sessionKey]) { + setStore("sessionTabs", sessionKey, { all: current.all, active: tab }) + return + } + setStore("sessionTabs", sessionKey, "active", tab) + }, + close(tab: string) { + const current = store.sessionTabs[sessionKey] + if (!current) return + + const all = current.all.filter((x) => x !== tab) + batch(() => { + setStore("sessionTabs", sessionKey, "all", all) + if (current.active !== tab) return + + const index = current.all.findIndex((f) => f === tab) + const next = all[index - 1] ?? all[0] + setStore("sessionTabs", sessionKey, "active", next) + }) + }, + move(tab: string, to: number) { + const current = store.sessionTabs[sessionKey] + if (!current) return + const index = current.all.findIndex((f) => f === tab) + if (index === -1) return + setStore( + "sessionTabs", + sessionKey, + "all", + produce((opened) => { + opened.splice(to, 0, opened.splice(index, 1)[0]) + }), + ) + }, + } + }, + } + }, +}) diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx new file mode 100644 index 00000000000..64bfa838dde --- /dev/null +++ b/packages/app/src/context/local.tsx @@ -0,0 +1,565 @@ +import { createStore, produce, reconcile } from "solid-js/store" +import { batch, createMemo, onCleanup } from "solid-js" +import { filter, firstBy, flat, groupBy, mapValues, pipe, uniqueBy, values } from "remeda" +import type { FileContent, FileNode, Model, Provider, File as FileStatus } from "@opencode-ai/sdk/v2" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { useSDK } from "./sdk" +import { useSync } from "./sync" +import { base64Encode } from "@opencode-ai/util/encode" +import { useProviders } from "@/hooks/use-providers" +import { DateTime } from "luxon" +import { Persist, persisted } from "@/utils/persist" +import { showToast } from "@opencode-ai/ui/toast" +import { useLanguage } from "@/context/language" + +export type LocalFile = FileNode & + Partial<{ + loaded: boolean + pinned: boolean + expanded: boolean + content: FileContent + selection: { startLine: number; startChar: number; endLine: number; endChar: number } + scrollTop: number + view: "raw" | "diff-unified" | "diff-split" + folded: string[] + selectedChange: number + status: FileStatus + }> +export type TextSelection = LocalFile["selection"] +export type View = LocalFile["view"] + +export type LocalModel = Omit & { + provider: Provider + latest?: boolean +} +export type ModelKey = { providerID: string; modelID: string } + +export type FileContext = { type: "file"; path: string; selection?: TextSelection } +export type ContextItem = FileContext + +export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ + name: "Local", + init: () => { + const sdk = useSDK() + const sync = useSync() + const providers = useProviders() + const language = useLanguage() + + function isModelValid(model: ModelKey) { + const provider = providers.all().find((x) => x.id === model.providerID) + return ( + !!provider?.models[model.modelID] && + providers + .connected() + .map((p) => p.id) + .includes(model.providerID) + ) + } + + function getFirstValidModel(...modelFns: (() => ModelKey | undefined)[]) { + for (const modelFn of modelFns) { + const model = modelFn() + if (!model) continue + if (isModelValid(model)) return model + } + } + + const agent = (() => { + const list = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent" && !x.hidden)) + const [store, setStore] = createStore<{ + current?: string + }>({ + current: list()[0]?.name, + }) + return { + list, + current() { + const available = list() + if (available.length === 0) return undefined + return available.find((x) => x.name === store.current) ?? available[0] + }, + set(name: string | undefined) { + const available = list() + if (available.length === 0) { + setStore("current", undefined) + return + } + if (name && available.some((x) => x.name === name)) { + setStore("current", name) + return + } + setStore("current", available[0].name) + }, + move(direction: 1 | -1) { + const available = list() + if (available.length === 0) { + setStore("current", undefined) + return + } + let next = available.findIndex((x) => x.name === store.current) + direction + if (next < 0) next = available.length - 1 + if (next >= available.length) next = 0 + const value = available[next] + if (!value) return + setStore("current", value.name) + if (value.model) + model.set({ + providerID: value.model.providerID, + modelID: value.model.modelID, + }) + }, + } + })() + + const model = (() => { + const [store, setStore, _, modelReady] = persisted( + Persist.global("model", ["model.v1"]), + createStore<{ + user: (ModelKey & { visibility: "show" | "hide"; favorite?: boolean })[] + recent: ModelKey[] + variant?: Record + }>({ + user: [], + recent: [], + variant: {}, + }), + ) + + const [ephemeral, setEphemeral] = createStore<{ + model: Record + }>({ + model: {}, + }) + + const available = createMemo(() => + providers.connected().flatMap((p) => + Object.values(p.models).map((m) => ({ + ...m, + provider: p, + })), + ), + ) + + const latest = createMemo(() => + pipe( + available(), + filter((x) => Math.abs(DateTime.fromISO(x.release_date).diffNow().as("months")) < 6), + groupBy((x) => x.provider.id), + mapValues((models) => + pipe( + models, + groupBy((x) => x.family), + values(), + (groups) => + groups.flatMap((g) => { + const first = firstBy(g, [(x) => x.release_date, "desc"]) + return first ? [{ modelID: first.id, providerID: first.provider.id }] : [] + }), + ), + ), + values(), + flat(), + ), + ) + + const latestSet = createMemo(() => new Set(latest().map((x) => `${x.providerID}:${x.modelID}`))) + + const userVisibilityMap = createMemo(() => { + const map = new Map() + for (const item of store.user) { + map.set(`${item.providerID}:${item.modelID}`, item.visibility) + } + return map + }) + + const list = createMemo(() => + available().map((m) => ({ + ...m, + name: m.name.replace("(latest)", "").trim(), + latest: m.name.includes("(latest)"), + })), + ) + + const find = (key: ModelKey) => list().find((m) => m.id === key?.modelID && m.provider.id === key.providerID) + + const fallbackModel = createMemo(() => { + if (sync.data.config.model) { + const [providerID, modelID] = sync.data.config.model.split("/") + if (isModelValid({ providerID, modelID })) { + return { + providerID, + modelID, + } + } + } + + for (const item of store.recent) { + if (isModelValid(item)) { + return item + } + } + + for (const p of providers.connected()) { + if (p.id in providers.default()) { + return { + providerID: p.id, + modelID: providers.default()[p.id], + } + } + } + + throw new Error("No default model found") + }) + + const current = createMemo(() => { + const a = agent.current() + if (!a) return undefined + const key = getFirstValidModel( + () => ephemeral.model[a.name], + () => a.model, + fallbackModel, + ) + if (!key) return undefined + return find(key) + }) + + const recent = createMemo(() => store.recent.map(find).filter(Boolean)) + + const cycle = (direction: 1 | -1) => { + const recentList = recent() + const currentModel = current() + if (!currentModel) return + + const index = recentList.findIndex( + (x) => x?.provider.id === currentModel.provider.id && x?.id === currentModel.id, + ) + if (index === -1) return + + let next = index + direction + if (next < 0) next = recentList.length - 1 + if (next >= recentList.length) next = 0 + + const val = recentList[next] + if (!val) return + + model.set({ + providerID: val.provider.id, + modelID: val.id, + }) + } + + function updateVisibility(model: ModelKey, visibility: "show" | "hide") { + const index = store.user.findIndex((x) => x.modelID === model.modelID && x.providerID === model.providerID) + if (index >= 0) { + setStore("user", index, { visibility }) + } else { + setStore("user", store.user.length, { ...model, visibility }) + } + } + + return { + ready: modelReady, + current, + recent, + list, + cycle, + set(model: ModelKey | undefined, options?: { recent?: boolean }) { + batch(() => { + const currentAgent = agent.current() + if (currentAgent) setEphemeral("model", currentAgent.name, model ?? fallbackModel()) + if (model) updateVisibility(model, "show") + if (options?.recent && model) { + const uniq = uniqueBy([model, ...store.recent], (x) => x.providerID + x.modelID) + if (uniq.length > 5) uniq.pop() + setStore("recent", uniq) + } + }) + }, + visible(model: ModelKey) { + const key = `${model.providerID}:${model.modelID}` + const visibility = userVisibilityMap().get(key) + if (visibility === "hide") return false + if (visibility === "show") return true + if (latestSet().has(key)) return true + // For models without valid release_date (e.g. custom models), show by default + const m = find(model) + if (!m?.release_date || !DateTime.fromISO(m.release_date).isValid) return true + return false + }, + setVisibility(model: ModelKey, visible: boolean) { + updateVisibility(model, visible ? "show" : "hide") + }, + variant: { + current() { + const m = current() + if (!m) return undefined + const key = `${m.provider.id}/${m.id}` + return store.variant?.[key] + }, + list() { + const m = current() + if (!m) return [] + if (!m.variants) return [] + return Object.keys(m.variants) + }, + set(value: string | undefined) { + const m = current() + if (!m) return + const key = `${m.provider.id}/${m.id}` + if (!store.variant) { + setStore("variant", { [key]: value }) + } else { + setStore("variant", key, value) + } + }, + cycle() { + const variants = this.list() + if (variants.length === 0) return + const currentVariant = this.current() + if (!currentVariant) { + this.set(variants[0]) + return + } + const index = variants.indexOf(currentVariant) + if (index === -1 || index === variants.length - 1) { + this.set(undefined) + return + } + this.set(variants[index + 1]) + }, + }, + } + })() + + const file = (() => { + const [store, setStore] = createStore<{ + node: Record + }>({ + node: {}, // Object.fromEntries(sync.data.node.map((x) => [x.path, x])), + }) + + // const changeset = createMemo(() => new Set(sync.data.changes.map((f) => f.path))) + // const changes = createMemo(() => Array.from(changeset()).sort((a, b) => a.localeCompare(b))) + + // createEffect((prev: FileStatus[]) => { + // const removed = prev.filter((p) => !sync.data.changes.find((c) => c.path === p.path)) + // for (const p of removed) { + // setStore( + // "node", + // p.path, + // produce((draft) => { + // draft.status = undefined + // draft.view = "raw" + // }), + // ) + // load(p.path) + // } + // for (const p of sync.data.changes) { + // if (store.node[p.path] === undefined) { + // fetch(p.path).then(() => { + // if (store.node[p.path] === undefined) return + // setStore("node", p.path, "status", p) + // }) + // } else { + // setStore("node", p.path, "status", p) + // } + // } + // return sync.data.changes + // }, sync.data.changes) + + // const changed = (path: string) => { + // const node = store.node[path] + // if (node?.status) return true + // const set = changeset() + // if (set.has(path)) return true + // for (const p of set) { + // if (p.startsWith(path ? path + "/" : "")) return true + // } + // return false + // } + + // const resetNode = (path: string) => { + // setStore("node", path, { + // loaded: undefined, + // pinned: undefined, + // content: undefined, + // selection: undefined, + // scrollTop: undefined, + // folded: undefined, + // view: undefined, + // selectedChange: undefined, + // }) + // } + + const relative = (path: string) => path.replace(sync.data.path.directory + "/", "") + + const load = async (path: string) => { + const relativePath = relative(path) + await sdk.client.file + .read({ path: relativePath }) + .then((x) => { + if (!store.node[relativePath]) return + setStore( + "node", + relativePath, + produce((draft) => { + draft.loaded = true + draft.content = x.data + }), + ) + }) + .catch((e) => { + showToast({ + variant: "error", + title: language.t("toast.file.loadFailed.title"), + description: e.message, + }) + }) + } + + const fetch = async (path: string) => { + const relativePath = relative(path) + const parent = relativePath.split("/").slice(0, -1).join("/") + if (parent) { + await list(parent) + } + } + + const init = async (path: string) => { + const relativePath = relative(path) + if (!store.node[relativePath]) await fetch(path) + if (store.node[relativePath]?.loaded) return + return load(relativePath) + } + + const open = async (path: string, options?: { pinned?: boolean; view?: LocalFile["view"] }) => { + const relativePath = relative(path) + if (!store.node[relativePath]) await fetch(path) + // setStore("opened", (x) => { + // if (x.includes(relativePath)) return x + // return [ + // ...opened() + // .filter((x) => x.pinned) + // .map((x) => x.path), + // relativePath, + // ] + // }) + // setStore("active", relativePath) + // context.addActive() + if (options?.pinned) setStore("node", path, "pinned", true) + if (options?.view && store.node[relativePath].view === undefined) setStore("node", path, "view", options.view) + if (store.node[relativePath]?.loaded) return + return load(relativePath) + } + + const list = async (path: string) => { + return sdk.client.file + .list({ path: path + "/" }) + .then((x) => { + setStore( + "node", + produce((draft) => { + x.data!.forEach((node) => { + if (node.path in draft) return + draft[node.path] = node + }) + }), + ) + }) + .catch(() => {}) + } + + const searchFiles = (query: string) => sdk.client.find.files({ query, dirs: "false" }).then((x) => x.data!) + const searchFilesAndDirectories = (query: string) => + sdk.client.find.files({ query, dirs: "true" }).then((x) => x.data!) + + const unsub = sdk.event.listen((e) => { + const event = e.details + switch (event.type) { + case "file.watcher.updated": + const relativePath = relative(event.properties.file) + if (relativePath.startsWith(".git/")) return + if (store.node[relativePath]) load(relativePath) + break + } + }) + onCleanup(unsub) + + return { + node: async (path: string) => { + if (!store.node[path] || !store.node[path].loaded) { + await init(path) + } + return store.node[path] + }, + update: (path: string, node: LocalFile) => setStore("node", path, reconcile(node)), + open, + load, + init, + expand(path: string) { + setStore("node", path, "expanded", true) + if (store.node[path]?.loaded) return + setStore("node", path, "loaded", true) + list(path) + }, + collapse(path: string) { + setStore("node", path, "expanded", false) + }, + select(path: string, selection: TextSelection | undefined) { + setStore("node", path, "selection", selection) + }, + scroll(path: string, scrollTop: number) { + setStore("node", path, "scrollTop", scrollTop) + }, + view(path: string): View { + const n = store.node[path] + return n && n.view ? n.view : "raw" + }, + setView(path: string, view: View) { + setStore("node", path, "view", view) + }, + unfold(path: string, key: string) { + setStore("node", path, "folded", (xs) => { + const a = xs ?? [] + if (a.includes(key)) return a + return [...a, key] + }) + }, + fold(path: string, key: string) { + setStore("node", path, "folded", (xs) => (xs ?? []).filter((k) => k !== key)) + }, + folded(path: string) { + const n = store.node[path] + return n && n.folded ? n.folded : [] + }, + changeIndex(path: string) { + return store.node[path]?.selectedChange + }, + setChangeIndex(path: string, index: number | undefined) { + setStore("node", path, "selectedChange", index) + }, + // changes, + // changed, + children(path: string) { + return Object.values(store.node).filter( + (x) => + x.path.startsWith(path) && + x.path !== path && + !x.path.replace(new RegExp(`^${path + "/"}`), "").includes("/"), + ) + }, + searchFiles, + searchFilesAndDirectories, + relative, + } + })() + + const result = { + slug: createMemo(() => base64Encode(sdk.directory)), + model, + agent, + file, + } + return result + }, +}) diff --git a/packages/app/src/context/notification.tsx b/packages/app/src/context/notification.tsx new file mode 100644 index 00000000000..58e7fbf83aa --- /dev/null +++ b/packages/app/src/context/notification.tsx @@ -0,0 +1,173 @@ +import { createStore } from "solid-js/store" +import { createEffect, onCleanup } from "solid-js" +import { useParams } from "@solidjs/router" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { useGlobalSDK } from "./global-sdk" +import { useGlobalSync } from "./global-sync" +import { usePlatform } from "@/context/platform" +import { useLanguage } from "@/context/language" +import { useSettings } from "@/context/settings" +import { Binary } from "@opencode-ai/util/binary" +import { base64Decode, base64Encode } from "@opencode-ai/util/encode" +import { EventSessionError } from "@opencode-ai/sdk/v2" +import { Persist, persisted } from "@/utils/persist" +import { playSound, soundSrc } from "@/utils/sound" + +type NotificationBase = { + directory?: string + session?: string + metadata?: any + time: number + viewed: boolean +} + +type TurnCompleteNotification = NotificationBase & { + type: "turn-complete" +} + +type ErrorNotification = NotificationBase & { + type: "error" + error: EventSessionError["properties"]["error"] +} + +export type Notification = TurnCompleteNotification | ErrorNotification + +const MAX_NOTIFICATIONS = 500 +const NOTIFICATION_TTL_MS = 1000 * 60 * 60 * 24 * 30 + +function pruneNotifications(list: Notification[]) { + const cutoff = Date.now() - NOTIFICATION_TTL_MS + const pruned = list.filter((n) => n.time >= cutoff) + if (pruned.length <= MAX_NOTIFICATIONS) return pruned + return pruned.slice(pruned.length - MAX_NOTIFICATIONS) +} + +export const { use: useNotification, provider: NotificationProvider } = createSimpleContext({ + name: "Notification", + init: () => { + const params = useParams() + const globalSDK = useGlobalSDK() + const globalSync = useGlobalSync() + const platform = usePlatform() + const settings = useSettings() + const language = useLanguage() + + const [store, setStore, _, ready] = persisted( + Persist.global("notification", ["notification.v1"]), + createStore({ + list: [] as Notification[], + }), + ) + + const meta = { pruned: false } + + createEffect(() => { + if (!ready()) return + if (meta.pruned) return + meta.pruned = true + setStore("list", pruneNotifications(store.list)) + }) + + const append = (notification: Notification) => { + setStore("list", (list) => pruneNotifications([...list, notification])) + } + + const unsub = globalSDK.event.listen((e) => { + const directory = e.name + const event = e.details + const time = Date.now() + const activeDirectory = params.dir ? base64Decode(params.dir) : undefined + const activeSession = params.id + const viewed = (sessionID?: string) => { + if (!activeDirectory) return false + if (!activeSession) return false + if (!sessionID) return false + if (directory !== activeDirectory) return false + return sessionID === activeSession + } + switch (event.type) { + case "session.idle": { + const sessionID = event.properties.sessionID + const [syncStore] = globalSync.child(directory) + const match = Binary.search(syncStore.session, sessionID, (s) => s.id) + const session = match.found ? syncStore.session[match.index] : undefined + if (session?.parentID) break + + playSound(soundSrc(settings.sounds.agent())) + + append({ + directory, + time, + viewed: viewed(sessionID), + type: "turn-complete", + session: sessionID, + }) + + const href = `/${base64Encode(directory)}/session/${sessionID}` + if (settings.notifications.agent()) { + void platform.notify( + language.t("notification.session.responseReady.title"), + session?.title ?? sessionID, + href, + ) + } + break + } + case "session.error": { + const sessionID = event.properties.sessionID + const [syncStore] = globalSync.child(directory) + const match = sessionID ? Binary.search(syncStore.session, sessionID, (s) => s.id) : undefined + const session = sessionID && match?.found ? syncStore.session[match.index] : undefined + if (session?.parentID) break + + playSound(soundSrc(settings.sounds.errors())) + + const error = "error" in event.properties ? event.properties.error : undefined + append({ + directory, + time, + viewed: viewed(sessionID), + type: "error", + session: sessionID ?? "global", + error, + }) + const description = + session?.title ?? + (typeof error === "string" ? error : language.t("notification.session.error.fallbackDescription")) + const href = sessionID ? `/${base64Encode(directory)}/session/${sessionID}` : `/${base64Encode(directory)}` + if (settings.notifications.errors()) { + void platform.notify(language.t("notification.session.error.title"), description, href) + } + break + } + } + }) + onCleanup(unsub) + + return { + ready, + session: { + all(session: string) { + return store.list.filter((n) => n.session === session) + }, + unseen(session: string) { + return store.list.filter((n) => n.session === session && !n.viewed) + }, + markViewed(session: string) { + setStore("list", (n) => n.session === session, "viewed", true) + }, + }, + project: { + all(directory: string) { + return store.list.filter((n) => n.directory === directory) + }, + unseen(directory: string) { + return store.list.filter((n) => n.directory === directory && !n.viewed) + }, + markViewed(directory: string) { + setStore("list", (n) => n.directory === directory, "viewed", true) + }, + }, + } + }, +}) diff --git a/packages/app/src/context/permission.tsx b/packages/app/src/context/permission.tsx new file mode 100644 index 00000000000..52878ba8f80 --- /dev/null +++ b/packages/app/src/context/permission.tsx @@ -0,0 +1,167 @@ +import { createMemo, onCleanup } from "solid-js" +import { createStore, produce } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import type { PermissionRequest } from "@opencode-ai/sdk/v2/client" +import { Persist, persisted } from "@/utils/persist" +import { useGlobalSDK } from "@/context/global-sdk" +import { useGlobalSync } from "./global-sync" +import { useParams } from "@solidjs/router" +import { base64Decode, base64Encode } from "@opencode-ai/util/encode" + +type PermissionRespondFn = (input: { + sessionID: string + permissionID: string + response: "once" | "always" | "reject" + directory?: string +}) => void + +function shouldAutoAccept(perm: PermissionRequest) { + return perm.permission === "edit" +} + +function isNonAllowRule(rule: unknown) { + if (!rule) return false + if (typeof rule === "string") return rule !== "allow" + if (typeof rule !== "object") return false + if (Array.isArray(rule)) return false + + for (const action of Object.values(rule)) { + if (action !== "allow") return true + } + + return false +} + +function hasAutoAcceptPermissionConfig(permission: unknown) { + if (!permission) return false + if (typeof permission === "string") return permission !== "allow" + if (typeof permission !== "object") return false + if (Array.isArray(permission)) return false + + const config = permission as Record + if (isNonAllowRule(config.edit)) return true + if (isNonAllowRule(config.write)) return true + + return false +} + +export const { use: usePermission, provider: PermissionProvider } = createSimpleContext({ + name: "Permission", + init: () => { + const params = useParams() + const globalSDK = useGlobalSDK() + const globalSync = useGlobalSync() + + const permissionsEnabled = createMemo(() => { + const directory = params.dir ? base64Decode(params.dir) : undefined + if (!directory) return false + const [store] = globalSync.child(directory) + return hasAutoAcceptPermissionConfig(store.config.permission) + }) + + const [store, setStore, _, ready] = persisted( + Persist.global("permission", ["permission.v3"]), + createStore({ + autoAcceptEdits: {} as Record, + }), + ) + + const responded = new Set() + + const respond: PermissionRespondFn = (input) => { + globalSDK.client.permission.respond(input).catch(() => { + responded.delete(input.permissionID) + }) + } + + function respondOnce(permission: PermissionRequest, directory?: string) { + if (responded.has(permission.id)) return + responded.add(permission.id) + respond({ + sessionID: permission.sessionID, + permissionID: permission.id, + response: "once", + directory, + }) + } + + function acceptKey(sessionID: string, directory?: string) { + if (!directory) return sessionID + return `${base64Encode(directory)}/${sessionID}` + } + + function isAutoAccepting(sessionID: string, directory?: string) { + const key = acceptKey(sessionID, directory) + return store.autoAcceptEdits[key] ?? store.autoAcceptEdits[sessionID] ?? false + } + + const unsubscribe = globalSDK.event.listen((e) => { + const event = e.details + if (event?.type !== "permission.asked") return + + const perm = event.properties + if (!isAutoAccepting(perm.sessionID, e.name)) return + if (!shouldAutoAccept(perm)) return + + respondOnce(perm, e.name) + }) + onCleanup(unsubscribe) + + function enable(sessionID: string, directory: string) { + const key = acceptKey(sessionID, directory) + setStore( + produce((draft) => { + draft.autoAcceptEdits[key] = true + delete draft.autoAcceptEdits[sessionID] + }), + ) + + globalSDK.client.permission + .list({ directory }) + .then((x) => { + for (const perm of x.data ?? []) { + if (!perm?.id) continue + if (perm.sessionID !== sessionID) continue + if (!shouldAutoAccept(perm)) continue + respondOnce(perm, directory) + } + }) + .catch(() => undefined) + } + + function disable(sessionID: string, directory?: string) { + const key = directory ? acceptKey(sessionID, directory) : undefined + setStore( + produce((draft) => { + if (key) delete draft.autoAcceptEdits[key] + delete draft.autoAcceptEdits[sessionID] + }), + ) + } + + return { + ready, + respond, + autoResponds(permission: PermissionRequest, directory?: string) { + return isAutoAccepting(permission.sessionID, directory) && shouldAutoAccept(permission) + }, + isAutoAccepting, + toggleAutoAccept(sessionID: string, directory: string) { + if (isAutoAccepting(sessionID, directory)) { + disable(sessionID, directory) + return + } + + enable(sessionID, directory) + }, + enableAutoAccept(sessionID: string, directory: string) { + if (isAutoAccepting(sessionID, directory)) return + enable(sessionID, directory) + }, + disableAutoAccept(sessionID: string, directory?: string) { + disable(sessionID, directory) + }, + permissionsEnabled, + } + }, +}) diff --git a/packages/app/src/context/platform.tsx b/packages/app/src/context/platform.tsx new file mode 100644 index 00000000000..89056b2c845 --- /dev/null +++ b/packages/app/src/context/platform.tsx @@ -0,0 +1,59 @@ +import { createSimpleContext } from "@opencode-ai/ui/context" +import { AsyncStorage, SyncStorage } from "@solid-primitives/storage" + +export type Platform = { + /** Platform discriminator */ + platform: "web" | "desktop" + + /** Desktop OS (Tauri only) */ + os?: "macos" | "windows" | "linux" + + /** App version */ + version?: string + + /** Open a URL in the default browser */ + openLink(url: string): void + + /** Restart the app */ + restart(): Promise + + /** Send a system notification (optional deep link) */ + notify(title: string, description?: string, href?: string): Promise + + /** Open directory picker dialog (native on Tauri, server-backed on web) */ + openDirectoryPickerDialog?(opts?: { title?: string; multiple?: boolean }): Promise + + /** Open native file picker dialog (Tauri only) */ + openFilePickerDialog?(opts?: { title?: string; multiple?: boolean }): Promise + + /** Save file picker dialog (Tauri only) */ + saveFilePickerDialog?(opts?: { title?: string; defaultPath?: string }): Promise + + /** Storage mechanism, defaults to localStorage */ + storage?: (name?: string) => SyncStorage | AsyncStorage + + /** Check for updates (Tauri only) */ + checkUpdate?(): Promise<{ updateAvailable: boolean; version?: string }> + + /** Install updates (Tauri only) */ + update?(): Promise + + /** Fetch override */ + fetch?: typeof fetch + + /** Get the configured default server URL (desktop only) */ + getDefaultServerUrl?(): Promise + + /** Set the default server URL to use on app startup (desktop only) */ + setDefaultServerUrl?(url: string | null): Promise + + /** Parse markdown to HTML using native parser (desktop only, returns unprocessed code blocks) */ + parseMarkdown?(markdown: string): Promise +} + +export const { use: usePlatform, provider: PlatformProvider } = createSimpleContext({ + name: "Platform", + init: (props: { value: Platform }) => { + return props.value + }, +}) diff --git a/packages/app/src/context/prompt.tsx b/packages/app/src/context/prompt.tsx new file mode 100644 index 00000000000..993d7e7a89a --- /dev/null +++ b/packages/app/src/context/prompt.tsx @@ -0,0 +1,244 @@ +import { createStore } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { batch, createMemo, createRoot, onCleanup } from "solid-js" +import { useParams } from "@solidjs/router" +import type { FileSelection } from "@/context/file" +import { Persist, persisted } from "@/utils/persist" + +interface PartBase { + content: string + start: number + end: number +} + +export interface TextPart extends PartBase { + type: "text" +} + +export interface FileAttachmentPart extends PartBase { + type: "file" + path: string + selection?: FileSelection +} + +export interface AgentPart extends PartBase { + type: "agent" + name: string +} + +export interface ImageAttachmentPart { + type: "image" + id: string + filename: string + mime: string + dataUrl: string +} + +export type ContentPart = TextPart | FileAttachmentPart | AgentPart | ImageAttachmentPart +export type Prompt = ContentPart[] + +export type FileContextItem = { + type: "file" + path: string + selection?: FileSelection +} + +export type ContextItem = FileContextItem + +export const DEFAULT_PROMPT: Prompt = [{ type: "text", content: "", start: 0, end: 0 }] + +function isSelectionEqual(a?: FileSelection, b?: FileSelection) { + if (!a && !b) return true + if (!a || !b) return false + return ( + a.startLine === b.startLine && a.startChar === b.startChar && a.endLine === b.endLine && a.endChar === b.endChar + ) +} + +export function isPromptEqual(promptA: Prompt, promptB: Prompt): boolean { + if (promptA.length !== promptB.length) return false + for (let i = 0; i < promptA.length; i++) { + const partA = promptA[i] + const partB = promptB[i] + if (partA.type !== partB.type) return false + if (partA.type === "text" && partA.content !== (partB as TextPart).content) { + return false + } + if (partA.type === "file") { + const fileA = partA as FileAttachmentPart + const fileB = partB as FileAttachmentPart + if (fileA.path !== fileB.path) return false + if (!isSelectionEqual(fileA.selection, fileB.selection)) return false + } + if (partA.type === "agent" && partA.name !== (partB as AgentPart).name) { + return false + } + if (partA.type === "image" && partA.id !== (partB as ImageAttachmentPart).id) { + return false + } + } + return true +} + +function cloneSelection(selection?: FileSelection) { + if (!selection) return undefined + return { ...selection } +} + +function clonePart(part: ContentPart): ContentPart { + if (part.type === "text") return { ...part } + if (part.type === "image") return { ...part } + if (part.type === "agent") return { ...part } + return { + ...part, + selection: cloneSelection(part.selection), + } +} + +function clonePrompt(prompt: Prompt): Prompt { + return prompt.map(clonePart) +} + +const WORKSPACE_KEY = "__workspace__" +const MAX_PROMPT_SESSIONS = 20 + +type PromptSession = ReturnType + +type PromptCacheEntry = { + value: PromptSession + dispose: VoidFunction +} + +function createPromptSession(dir: string, id: string | undefined) { + const legacy = `${dir}/prompt${id ? "/" + id : ""}.v2` + + const [store, setStore, _, ready] = persisted( + Persist.scoped(dir, id, "prompt", [legacy]), + createStore<{ + prompt: Prompt + cursor?: number + context: { + activeTab: boolean + items: (ContextItem & { key: string })[] + } + }>({ + prompt: clonePrompt(DEFAULT_PROMPT), + cursor: undefined, + context: { + activeTab: true, + items: [], + }, + }), + ) + + function keyForItem(item: ContextItem) { + if (item.type !== "file") return item.type + const start = item.selection?.startLine + const end = item.selection?.endLine + return `${item.type}:${item.path}:${start}:${end}` + } + + return { + ready, + current: createMemo(() => store.prompt), + cursor: createMemo(() => store.cursor), + dirty: createMemo(() => !isPromptEqual(store.prompt, DEFAULT_PROMPT)), + context: { + activeTab: createMemo(() => store.context.activeTab), + items: createMemo(() => store.context.items), + addActive() { + setStore("context", "activeTab", true) + }, + removeActive() { + setStore("context", "activeTab", false) + }, + add(item: ContextItem) { + const key = keyForItem(item) + if (store.context.items.find((x) => x.key === key)) return + setStore("context", "items", (items) => [...items, { key, ...item }]) + }, + remove(key: string) { + setStore("context", "items", (items) => items.filter((x) => x.key !== key)) + }, + }, + set(prompt: Prompt, cursorPosition?: number) { + const next = clonePrompt(prompt) + batch(() => { + setStore("prompt", next) + if (cursorPosition !== undefined) setStore("cursor", cursorPosition) + }) + }, + reset() { + batch(() => { + setStore("prompt", clonePrompt(DEFAULT_PROMPT)) + setStore("cursor", 0) + }) + }, + } +} + +export const { use: usePrompt, provider: PromptProvider } = createSimpleContext({ + name: "Prompt", + gate: false, + init: () => { + const params = useParams() + const cache = new Map() + + const disposeAll = () => { + for (const entry of cache.values()) { + entry.dispose() + } + cache.clear() + } + + onCleanup(disposeAll) + + const prune = () => { + while (cache.size > MAX_PROMPT_SESSIONS) { + const first = cache.keys().next().value + if (!first) return + const entry = cache.get(first) + entry?.dispose() + cache.delete(first) + } + } + + const load = (dir: string, id: string | undefined) => { + const key = `${dir}:${id ?? WORKSPACE_KEY}` + const existing = cache.get(key) + if (existing) { + cache.delete(key) + cache.set(key, existing) + return existing.value + } + + const entry = createRoot((dispose) => ({ + value: createPromptSession(dir, id), + dispose, + })) + + cache.set(key, entry) + prune() + return entry.value + } + + const session = createMemo(() => load(params.dir!, params.id)) + + return { + ready: () => session().ready(), + current: () => session().current(), + cursor: () => session().cursor(), + dirty: () => session().dirty(), + context: { + activeTab: () => session().context.activeTab(), + items: () => session().context.items(), + addActive: () => session().context.addActive(), + removeActive: () => session().context.removeActive(), + add: (item: ContextItem) => session().context.add(item), + remove: (key: string) => session().context.remove(key), + }, + set: (prompt: Prompt, cursorPosition?: number) => session().set(prompt, cursorPosition), + reset: () => session().reset(), + } + }, +}) diff --git a/packages/app/src/context/sdk.tsx b/packages/app/src/context/sdk.tsx new file mode 100644 index 00000000000..aa4820c4945 --- /dev/null +++ b/packages/app/src/context/sdk.tsx @@ -0,0 +1,31 @@ +import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2/client" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { createGlobalEmitter } from "@solid-primitives/event-bus" +import { onCleanup } from "solid-js" +import { useGlobalSDK } from "./global-sdk" +import { usePlatform } from "./platform" + +export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ + name: "SDK", + init: (props: { directory: string }) => { + const platform = usePlatform() + const globalSDK = useGlobalSDK() + const sdk = createOpencodeClient({ + baseUrl: globalSDK.url, + fetch: platform.fetch, + directory: props.directory, + throwOnError: true, + }) + + const emitter = createGlobalEmitter<{ + [key in Event["type"]]: Extract + }>() + + const unsub = globalSDK.event.on(props.directory, (event) => { + emitter.emit(event.type, event) + }) + onCleanup(unsub) + + return { directory: props.directory, client: sdk, event: emitter, url: globalSDK.url } + }, +}) diff --git a/packages/app/src/context/server.tsx b/packages/app/src/context/server.tsx new file mode 100644 index 00000000000..1076570928f --- /dev/null +++ b/packages/app/src/context/server.tsx @@ -0,0 +1,214 @@ +import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { batch, createEffect, createMemo, createSignal, onCleanup } from "solid-js" +import { createStore } from "solid-js/store" +import { usePlatform } from "@/context/platform" +import { Persist, persisted } from "@/utils/persist" + +type StoredProject = { worktree: string; expanded: boolean } + +export function normalizeServerUrl(input: string) { + const trimmed = input.trim() + if (!trimmed) return + const withProtocol = /^https?:\/\//.test(trimmed) ? trimmed : `http://${trimmed}` + return withProtocol.replace(/\/+$/, "") +} + +export function serverDisplayName(url: string) { + if (!url) return "" + return url.replace(/^https?:\/\//, "").replace(/\/+$/, "") +} + +function projectsKey(url: string) { + if (!url) return "" + const host = url.replace(/^https?:\/\//, "").split(":")[0] + if (host === "localhost" || host === "127.0.0.1") return "local" + return url +} + +export const { use: useServer, provider: ServerProvider } = createSimpleContext({ + name: "Server", + init: (props: { defaultUrl: string }) => { + const platform = usePlatform() + + const [store, setStore, _, ready] = persisted( + Persist.global("server", ["server.v3"]), + createStore({ + list: [] as string[], + projects: {} as Record, + lastProject: {} as Record, + }), + ) + + const [active, setActiveRaw] = createSignal("") + + function setActive(input: string) { + const url = normalizeServerUrl(input) + if (!url) return + setActiveRaw(url) + } + + function add(input: string) { + const url = normalizeServerUrl(input) + if (!url) return + + const fallback = normalizeServerUrl(props.defaultUrl) + if (fallback && url === fallback) { + setActiveRaw(url) + return + } + + batch(() => { + if (!store.list.includes(url)) { + setStore("list", store.list.length, url) + } + setActiveRaw(url) + }) + } + + function remove(input: string) { + const url = normalizeServerUrl(input) + if (!url) return + + const list = store.list.filter((x) => x !== url) + const next = active() === url ? (list[0] ?? normalizeServerUrl(props.defaultUrl) ?? "") : active() + + batch(() => { + setStore("list", list) + setActiveRaw(next) + }) + } + + createEffect(() => { + if (!ready()) return + if (active()) return + const url = normalizeServerUrl(props.defaultUrl) + if (!url) return + setActiveRaw(url) + }) + + const isReady = createMemo(() => ready() && !!active()) + + const [healthy, setHealthy] = createSignal(undefined) + + const check = (url: string) => { + const sdk = createOpencodeClient({ + baseUrl: url, + fetch: platform.fetch, + signal: AbortSignal.timeout(3000), + }) + return sdk.global + .health() + .then((x) => x.data?.healthy === true) + .catch(() => false) + } + + createEffect(() => { + const url = active() + if (!url) return + + setHealthy(undefined) + + let alive = true + let busy = false + + const run = () => { + if (busy) return + busy = true + void check(url) + .then((next) => { + if (!alive) return + setHealthy(next) + }) + .finally(() => { + busy = false + }) + } + + run() + const interval = setInterval(run, 10_000) + + onCleanup(() => { + alive = false + clearInterval(interval) + }) + }) + + const origin = createMemo(() => projectsKey(active())) + const projectsList = createMemo(() => store.projects[origin()] ?? []) + const isLocal = createMemo(() => origin() === "local") + + return { + ready: isReady, + healthy, + isLocal, + get url() { + return active() + }, + get name() { + return serverDisplayName(active()) + }, + get list() { + return store.list + }, + setActive, + add, + remove, + projects: { + list: projectsList, + open(directory: string) { + const key = origin() + if (!key) return + const current = store.projects[key] ?? [] + if (current.find((x) => x.worktree === directory)) return + setStore("projects", key, [{ worktree: directory, expanded: true }, ...current]) + }, + close(directory: string) { + const key = origin() + if (!key) return + const current = store.projects[key] ?? [] + setStore( + "projects", + key, + current.filter((x) => x.worktree !== directory), + ) + }, + expand(directory: string) { + const key = origin() + if (!key) return + const current = store.projects[key] ?? [] + const index = current.findIndex((x) => x.worktree === directory) + if (index !== -1) setStore("projects", key, index, "expanded", true) + }, + collapse(directory: string) { + const key = origin() + if (!key) return + const current = store.projects[key] ?? [] + const index = current.findIndex((x) => x.worktree === directory) + if (index !== -1) setStore("projects", key, index, "expanded", false) + }, + move(directory: string, toIndex: number) { + const key = origin() + if (!key) return + const current = store.projects[key] ?? [] + const fromIndex = current.findIndex((x) => x.worktree === directory) + if (fromIndex === -1 || fromIndex === toIndex) return + const result = [...current] + const [item] = result.splice(fromIndex, 1) + result.splice(toIndex, 0, item) + setStore("projects", key, result) + }, + last() { + const key = origin() + if (!key) return + return store.lastProject[key] + }, + touch(directory: string) { + const key = origin() + if (!key) return + setStore("lastProject", key, directory) + }, + }, + } + }, +}) diff --git a/packages/app/src/context/settings.tsx b/packages/app/src/context/settings.tsx new file mode 100644 index 00000000000..9211eacd2a8 --- /dev/null +++ b/packages/app/src/context/settings.tsx @@ -0,0 +1,158 @@ +import { createStore, reconcile } from "solid-js/store" +import { createEffect, createMemo } from "solid-js" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { persisted } from "@/utils/persist" + +export interface NotificationSettings { + agent: boolean + permissions: boolean + errors: boolean +} + +export interface SoundSettings { + agent: string + permissions: string + errors: string +} + +export interface Settings { + general: { + autoSave: boolean + } + appearance: { + fontSize: number + font: string + } + keybinds: Record + permissions: { + autoApprove: boolean + } + notifications: NotificationSettings + sounds: SoundSettings +} + +const defaultSettings: Settings = { + general: { + autoSave: true, + }, + appearance: { + fontSize: 14, + font: "ibm-plex-mono", + }, + keybinds: {}, + permissions: { + autoApprove: false, + }, + notifications: { + agent: true, + permissions: true, + errors: false, + }, + sounds: { + agent: "staplebops-01", + permissions: "staplebops-02", + errors: "nope-03", + }, +} + +const monoFallback = + 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace' + +const monoFonts: Record = { + "ibm-plex-mono": `"IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "cascadia-code": `"Cascadia Code Nerd Font", "Cascadia Code NF", "Cascadia Mono NF", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "fira-code": `"Fira Code Nerd Font", "FiraMono Nerd Font", "FiraMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + hack: `"Hack Nerd Font", "Hack Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + inconsolata: `"Inconsolata Nerd Font", "Inconsolata Nerd Font Mono","IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "intel-one-mono": `"Intel One Mono Nerd Font", "IntoneMono Nerd Font", "IntoneMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "jetbrains-mono": `"JetBrains Mono Nerd Font", "JetBrainsMono Nerd Font Mono", "JetBrainsMonoNL Nerd Font", "JetBrainsMonoNL Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "meslo-lgs": `"Meslo LGS Nerd Font", "MesloLGS Nerd Font", "MesloLGM Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "roboto-mono": `"Roboto Mono Nerd Font", "RobotoMono Nerd Font", "RobotoMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "source-code-pro": `"Source Code Pro Nerd Font", "SauceCodePro Nerd Font", "SauceCodePro Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "ubuntu-mono": `"Ubuntu Mono Nerd Font", "UbuntuMono Nerd Font", "UbuntuMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, +} + +export function monoFontFamily(font: string | undefined) { + return monoFonts[font ?? defaultSettings.appearance.font] ?? monoFonts[defaultSettings.appearance.font] +} + +export const { use: useSettings, provider: SettingsProvider } = createSimpleContext({ + name: "Settings", + init: () => { + const [store, setStore, _, ready] = persisted("settings.v3", createStore(defaultSettings)) + + createEffect(() => { + if (typeof document === "undefined") return + document.documentElement.style.setProperty("--font-family-mono", monoFontFamily(store.appearance?.font)) + }) + + return { + ready, + get current() { + return store + }, + general: { + autoSave: createMemo(() => store.general?.autoSave ?? defaultSettings.general.autoSave), + setAutoSave(value: boolean) { + setStore("general", "autoSave", value) + }, + }, + appearance: { + fontSize: createMemo(() => store.appearance?.fontSize ?? defaultSettings.appearance.fontSize), + setFontSize(value: number) { + setStore("appearance", "fontSize", value) + }, + font: createMemo(() => store.appearance?.font ?? defaultSettings.appearance.font), + setFont(value: string) { + setStore("appearance", "font", value) + }, + }, + keybinds: { + get: (action: string) => store.keybinds?.[action], + set(action: string, keybind: string) { + setStore("keybinds", action, keybind) + }, + reset(action: string) { + setStore("keybinds", action, undefined!) + }, + resetAll() { + setStore("keybinds", reconcile({})) + }, + }, + permissions: { + autoApprove: createMemo(() => store.permissions?.autoApprove ?? defaultSettings.permissions.autoApprove), + setAutoApprove(value: boolean) { + setStore("permissions", "autoApprove", value) + }, + }, + notifications: { + agent: createMemo(() => store.notifications?.agent ?? defaultSettings.notifications.agent), + setAgent(value: boolean) { + setStore("notifications", "agent", value) + }, + permissions: createMemo(() => store.notifications?.permissions ?? defaultSettings.notifications.permissions), + setPermissions(value: boolean) { + setStore("notifications", "permissions", value) + }, + errors: createMemo(() => store.notifications?.errors ?? defaultSettings.notifications.errors), + setErrors(value: boolean) { + setStore("notifications", "errors", value) + }, + }, + sounds: { + agent: createMemo(() => store.sounds?.agent ?? defaultSettings.sounds.agent), + setAgent(value: string) { + setStore("sounds", "agent", value) + }, + permissions: createMemo(() => store.sounds?.permissions ?? defaultSettings.sounds.permissions), + setPermissions(value: string) { + setStore("sounds", "permissions", value) + }, + errors: createMemo(() => store.sounds?.errors ?? defaultSettings.sounds.errors), + setErrors(value: string) { + setStore("sounds", "errors", value) + }, + }, + } + }, +}) diff --git a/packages/app/src/context/sync.tsx b/packages/app/src/context/sync.tsx new file mode 100644 index 00000000000..33129e1b475 --- /dev/null +++ b/packages/app/src/context/sync.tsx @@ -0,0 +1,256 @@ +import { batch, createMemo } from "solid-js" +import { createStore, produce, reconcile } from "solid-js/store" +import { Binary } from "@opencode-ai/util/binary" +import { retry } from "@opencode-ai/util/retry" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { useGlobalSync } from "./global-sync" +import { useSDK } from "./sdk" +import type { Message, Part } from "@opencode-ai/sdk/v2/client" + +export const { use: useSync, provider: SyncProvider } = createSimpleContext({ + name: "Sync", + init: () => { + const globalSync = useGlobalSync() + const sdk = useSDK() + const [store, setStore] = globalSync.child(sdk.directory) + const absolute = (path: string) => (store.path.directory + "/" + path).replace("//", "/") + const chunk = 400 + const inflight = new Map>() + const inflightDiff = new Map>() + const inflightTodo = new Map>() + const [meta, setMeta] = createStore({ + limit: {} as Record, + complete: {} as Record, + loading: {} as Record, + }) + + const getSession = (sessionID: string) => { + const match = Binary.search(store.session, sessionID, (s) => s.id) + if (match.found) return store.session[match.index] + return undefined + } + + const limitFor = (count: number) => { + if (count <= chunk) return chunk + return Math.ceil(count / chunk) * chunk + } + + const hydrateMessages = (sessionID: string) => { + if (meta.limit[sessionID] !== undefined) return + + const messages = store.message[sessionID] + if (!messages) return + + const limit = limitFor(messages.length) + setMeta("limit", sessionID, limit) + setMeta("complete", sessionID, messages.length < limit) + } + + const loadMessages = async (sessionID: string, limit: number) => { + if (meta.loading[sessionID]) return + + setMeta("loading", sessionID, true) + await retry(() => sdk.client.session.messages({ sessionID, limit })) + .then((messages) => { + const items = (messages.data ?? []).filter((x) => !!x?.info?.id) + const next = items + .map((x) => x.info) + .filter((m) => !!m?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + + batch(() => { + setStore("message", sessionID, reconcile(next, { key: "id" })) + + for (const message of items) { + setStore( + "part", + message.info.id, + reconcile( + message.parts + .filter((p) => !!p?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)), + { key: "id" }, + ), + ) + } + + setMeta("limit", sessionID, limit) + setMeta("complete", sessionID, next.length < limit) + }) + }) + .finally(() => { + setMeta("loading", sessionID, false) + }) + } + + return { + data: store, + set: setStore, + get status() { + return store.status + }, + get ready() { + return store.status !== "loading" + }, + get project() { + const match = Binary.search(globalSync.data.project, store.project, (p) => p.id) + if (match.found) return globalSync.data.project[match.index] + return undefined + }, + session: { + get: getSession, + addOptimisticMessage(input: { + sessionID: string + messageID: string + parts: Part[] + agent: string + model: { providerID: string; modelID: string } + }) { + const message: Message = { + id: input.messageID, + sessionID: input.sessionID, + role: "user", + time: { created: Date.now() }, + agent: input.agent, + model: input.model, + } + setStore( + produce((draft) => { + const messages = draft.message[input.sessionID] + if (!messages) { + draft.message[input.sessionID] = [message] + } else { + const result = Binary.search(messages, input.messageID, (m) => m.id) + messages.splice(result.index, 0, message) + } + draft.part[input.messageID] = input.parts + .filter((p) => !!p?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + }), + ) + }, + async sync(sessionID: string) { + const hasSession = getSession(sessionID) !== undefined + hydrateMessages(sessionID) + + const hasMessages = store.message[sessionID] !== undefined + if (hasSession && hasMessages) return + + const pending = inflight.get(sessionID) + if (pending) return pending + + const limit = meta.limit[sessionID] ?? chunk + + const sessionReq = hasSession + ? Promise.resolve() + : retry(() => sdk.client.session.get({ sessionID })).then((session) => { + const data = session.data + if (!data) return + setStore( + "session", + produce((draft) => { + const match = Binary.search(draft, sessionID, (s) => s.id) + if (match.found) { + draft[match.index] = data + return + } + draft.splice(match.index, 0, data) + }), + ) + }) + + const messagesReq = hasMessages ? Promise.resolve() : loadMessages(sessionID, limit) + + const promise = Promise.all([sessionReq, messagesReq]) + .then(() => {}) + .finally(() => { + inflight.delete(sessionID) + }) + + inflight.set(sessionID, promise) + return promise + }, + async diff(sessionID: string) { + if (store.session_diff[sessionID] !== undefined) return + + const pending = inflightDiff.get(sessionID) + if (pending) return pending + + const promise = retry(() => sdk.client.session.diff({ sessionID })) + .then((diff) => { + setStore("session_diff", sessionID, reconcile(diff.data ?? [], { key: "file" })) + }) + .finally(() => { + inflightDiff.delete(sessionID) + }) + + inflightDiff.set(sessionID, promise) + return promise + }, + async todo(sessionID: string) { + if (store.todo[sessionID] !== undefined) return + + const pending = inflightTodo.get(sessionID) + if (pending) return pending + + const promise = retry(() => sdk.client.session.todo({ sessionID })) + .then((todo) => { + setStore("todo", sessionID, reconcile(todo.data ?? [], { key: "id" })) + }) + .finally(() => { + inflightTodo.delete(sessionID) + }) + + inflightTodo.set(sessionID, promise) + return promise + }, + history: { + more(sessionID: string) { + if (store.message[sessionID] === undefined) return false + if (meta.limit[sessionID] === undefined) return false + if (meta.complete[sessionID]) return false + return true + }, + loading(sessionID: string) { + return meta.loading[sessionID] ?? false + }, + async loadMore(sessionID: string, count = chunk) { + if (meta.loading[sessionID]) return + if (meta.complete[sessionID]) return + + const current = meta.limit[sessionID] ?? chunk + await loadMessages(sessionID, current + count) + }, + }, + fetch: async (count = 10) => { + setStore("limit", (x) => x + count) + await sdk.client.session.list().then((x) => { + const sessions = (x.data ?? []) + .filter((s) => !!s?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + .slice(0, store.limit) + setStore("session", reconcile(sessions, { key: "id" })) + }) + }, + more: createMemo(() => store.session.length >= store.limit), + archive: async (sessionID: string) => { + await sdk.client.session.update({ sessionID, time: { archived: Date.now() } }) + setStore( + produce((draft) => { + const match = Binary.search(draft.session, sessionID, (s) => s.id) + if (match.found) draft.session.splice(match.index, 1) + }), + ) + }, + }, + absolute, + get directory() { + return store.path.directory + }, + } + }, +}) diff --git a/packages/app/src/context/terminal.tsx b/packages/app/src/context/terminal.tsx new file mode 100644 index 00000000000..147c4f8f7ea --- /dev/null +++ b/packages/app/src/context/terminal.tsx @@ -0,0 +1,267 @@ +import { createStore, produce } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { batch, createEffect, createMemo, createRoot, onCleanup } from "solid-js" +import { useParams } from "@solidjs/router" +import { useSDK } from "./sdk" +import { Persist, persisted } from "@/utils/persist" + +export type LocalPTY = { + id: string + title: string + titleNumber: number + rows?: number + cols?: number + buffer?: string + scrollY?: number + error?: boolean +} + +const WORKSPACE_KEY = "__workspace__" +const MAX_TERMINAL_SESSIONS = 20 + +type TerminalSession = ReturnType + +type TerminalCacheEntry = { + value: TerminalSession + dispose: VoidFunction +} + +function createTerminalSession(sdk: ReturnType, dir: string, session?: string) { + const legacy = session ? [`${dir}/terminal/${session}.v1`, `${dir}/terminal.v1`] : [`${dir}/terminal.v1`] + + const numberFromTitle = (title: string) => { + const match = title.match(/^Terminal (\d+)$/) + if (!match) return + const value = Number(match[1]) + if (!Number.isFinite(value) || value <= 0) return + return value + } + + const [store, setStore, _, ready] = persisted( + Persist.workspace(dir, "terminal", legacy), + createStore<{ + active?: string + all: LocalPTY[] + }>({ + all: [], + }), + ) + + const unsub = sdk.event.on("pty.exited", (event) => { + const id = event.properties.id + if (!store.all.some((x) => x.id === id)) return + batch(() => { + setStore( + "all", + store.all.filter((x) => x.id !== id), + ) + if (store.active === id) { + const remaining = store.all.filter((x) => x.id !== id) + setStore("active", remaining[0]?.id) + } + }) + }) + onCleanup(unsub) + + const meta = { migrated: false } + + createEffect(() => { + if (!ready()) return + if (meta.migrated) return + meta.migrated = true + + setStore("all", (all) => { + const next = all.map((pty) => { + const direct = Number.isFinite(pty.titleNumber) && pty.titleNumber > 0 ? pty.titleNumber : undefined + if (direct !== undefined) return pty + const parsed = numberFromTitle(pty.title) + if (parsed === undefined) return pty + return { ...pty, titleNumber: parsed } + }) + if (next.every((pty, index) => pty === all[index])) return all + return next + }) + }) + + return { + ready, + all: createMemo(() => Object.values(store.all)), + active: createMemo(() => store.active), + new() { + const existingTitleNumbers = new Set( + store.all.flatMap((pty) => { + const direct = Number.isFinite(pty.titleNumber) && pty.titleNumber > 0 ? pty.titleNumber : undefined + if (direct !== undefined) return [direct] + const parsed = numberFromTitle(pty.title) + if (parsed === undefined) return [] + return [parsed] + }), + ) + + const nextNumber = + Array.from({ length: existingTitleNumbers.size + 1 }, (_, index) => index + 1).find( + (number) => !existingTitleNumbers.has(number), + ) ?? 1 + + sdk.client.pty + .create({ title: `Terminal ${nextNumber}` }) + .then((pty) => { + const id = pty.data?.id + if (!id) return + const newTerminal = { + id, + title: pty.data?.title ?? "Terminal", + titleNumber: nextNumber, + } + setStore("all", (all) => { + const newAll = [...all, newTerminal] + return newAll + }) + setStore("active", id) + }) + .catch((e) => { + console.error("Failed to create terminal", e) + }) + }, + update(pty: Partial & { id: string }) { + const index = store.all.findIndex((x) => x.id === pty.id) + if (index !== -1) { + setStore("all", index, (existing) => ({ ...existing, ...pty })) + } + sdk.client.pty + .update({ + ptyID: pty.id, + title: pty.title, + size: pty.cols && pty.rows ? { rows: pty.rows, cols: pty.cols } : undefined, + }) + .catch((e) => { + console.error("Failed to update terminal", e) + }) + }, + async clone(id: string) { + const index = store.all.findIndex((x) => x.id === id) + const pty = store.all[index] + if (!pty) return + const clone = await sdk.client.pty + .create({ + title: pty.title, + }) + .catch((e) => { + console.error("Failed to clone terminal", e) + return undefined + }) + if (!clone?.data) return + setStore("all", index, { + ...pty, + ...clone.data, + }) + if (store.active === pty.id) { + setStore("active", clone.data.id) + } + }, + open(id: string) { + setStore("active", id) + }, + next() { + const index = store.all.findIndex((x) => x.id === store.active) + if (index === -1) return + const nextIndex = (index + 1) % store.all.length + setStore("active", store.all[nextIndex]?.id) + }, + previous() { + const index = store.all.findIndex((x) => x.id === store.active) + if (index === -1) return + const prevIndex = index === 0 ? store.all.length - 1 : index - 1 + setStore("active", store.all[prevIndex]?.id) + }, + async close(id: string) { + batch(() => { + const filtered = store.all.filter((x) => x.id !== id) + if (store.active === id) { + const index = store.all.findIndex((f) => f.id === id) + const next = index > 0 ? index - 1 : 0 + setStore("active", filtered[next]?.id) + } + setStore("all", filtered) + }) + + await sdk.client.pty.remove({ ptyID: id }).catch((e) => { + console.error("Failed to close terminal", e) + }) + }, + move(id: string, to: number) { + const index = store.all.findIndex((f) => f.id === id) + if (index === -1) return + setStore( + "all", + produce((all) => { + all.splice(to, 0, all.splice(index, 1)[0]) + }), + ) + }, + } +} + +export const { use: useTerminal, provider: TerminalProvider } = createSimpleContext({ + name: "Terminal", + gate: false, + init: () => { + const sdk = useSDK() + const params = useParams() + const cache = new Map() + + const disposeAll = () => { + for (const entry of cache.values()) { + entry.dispose() + } + cache.clear() + } + + onCleanup(disposeAll) + + const prune = () => { + while (cache.size > MAX_TERMINAL_SESSIONS) { + const first = cache.keys().next().value + if (!first) return + const entry = cache.get(first) + entry?.dispose() + cache.delete(first) + } + } + + const load = (dir: string, session?: string) => { + const key = `${dir}:${WORKSPACE_KEY}` + const existing = cache.get(key) + if (existing) { + cache.delete(key) + cache.set(key, existing) + return existing.value + } + + const entry = createRoot((dispose) => ({ + value: createTerminalSession(sdk, dir, session), + dispose, + })) + + cache.set(key, entry) + prune() + return entry.value + } + + const workspace = createMemo(() => load(params.dir!, params.id)) + + return { + ready: () => workspace().ready(), + all: () => workspace().all(), + active: () => workspace().active(), + new: () => workspace().new(), + update: (pty: Partial & { id: string }) => workspace().update(pty), + clone: (id: string) => workspace().clone(id), + open: (id: string) => workspace().open(id), + close: (id: string) => workspace().close(id), + move: (id: string, to: number) => workspace().move(id, to), + next: () => workspace().next(), + previous: () => workspace().previous(), + } + }, +}) diff --git a/packages/app/src/custom-elements.d.ts b/packages/app/src/custom-elements.d.ts new file mode 120000 index 00000000000..e4ea0d6cebd --- /dev/null +++ b/packages/app/src/custom-elements.d.ts @@ -0,0 +1 @@ +../../ui/src/custom-elements.d.ts \ No newline at end of file diff --git a/packages/app/src/entry.tsx b/packages/app/src/entry.tsx new file mode 100644 index 00000000000..df8547636b4 --- /dev/null +++ b/packages/app/src/entry.tsx @@ -0,0 +1,76 @@ +// @refresh reload +import { render } from "solid-js/web" +import { AppBaseProviders, AppInterface } from "@/app" +import { Platform, PlatformProvider } from "@/context/platform" +import { dict as en } from "@/i18n/en" +import { dict as zh } from "@/i18n/zh" +import pkg from "../package.json" + +const root = document.getElementById("root") +if (import.meta.env.DEV && !(root instanceof HTMLElement)) { + const locale = (() => { + if (typeof navigator !== "object") return "en" as const + const languages = navigator.languages?.length ? navigator.languages : [navigator.language] + for (const language of languages) { + if (!language) continue + if (language.toLowerCase().startsWith("zh")) return "zh" as const + } + return "en" as const + })() + + const key = "error.dev.rootNotFound" as const + const message = locale === "zh" ? (zh[key] ?? en[key]) : en[key] + throw new Error(message) +} + +const platform: Platform = { + platform: "web", + version: pkg.version, + openLink(url: string) { + window.open(url, "_blank") + }, + restart: async () => { + window.location.reload() + }, + notify: async (title, description, href) => { + if (!("Notification" in window)) return + + const permission = + Notification.permission === "default" + ? await Notification.requestPermission().catch(() => "denied") + : Notification.permission + + if (permission !== "granted") return + + const inView = document.visibilityState === "visible" && document.hasFocus() + if (inView) return + + await Promise.resolve() + .then(() => { + const notification = new Notification(title, { + body: description ?? "", + icon: "https://opencode.ai/favicon-96x96-v3.png", + }) + notification.onclick = () => { + window.focus() + if (href) { + window.history.pushState(null, "", href) + window.dispatchEvent(new PopStateEvent("popstate")) + } + notification.close() + } + }) + .catch(() => undefined) + }, +} + +render( + () => ( + + + + + + ), + root!, +) diff --git a/packages/app/src/env.d.ts b/packages/app/src/env.d.ts new file mode 100644 index 00000000000..ad575e93b4a --- /dev/null +++ b/packages/app/src/env.d.ts @@ -0,0 +1,8 @@ +interface ImportMetaEnv { + readonly VITE_OPENCODE_SERVER_HOST: string + readonly VITE_OPENCODE_SERVER_PORT: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/packages/app/src/hooks/use-providers.ts b/packages/app/src/hooks/use-providers.ts new file mode 100644 index 00000000000..4a73fa05588 --- /dev/null +++ b/packages/app/src/hooks/use-providers.ts @@ -0,0 +1,31 @@ +import { useGlobalSync } from "@/context/global-sync" +import { base64Decode } from "@opencode-ai/util/encode" +import { useParams } from "@solidjs/router" +import { createMemo } from "solid-js" + +export const popularProviders = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"] + +export function useProviders() { + const globalSync = useGlobalSync() + const params = useParams() + const currentDirectory = createMemo(() => base64Decode(params.dir ?? "")) + const providers = createMemo(() => { + if (currentDirectory()) { + const [projectStore] = globalSync.child(currentDirectory()) + return projectStore.provider + } + return globalSync.data.provider + }) + const connected = createMemo(() => providers().all.filter((p) => providers().connected.includes(p.id))) + const paid = createMemo(() => + connected().filter((p) => p.id !== "opencode" || Object.values(p.models).find((m) => m.cost?.input)), + ) + const popular = createMemo(() => providers().all.filter((p) => popularProviders.includes(p.id))) + return { + all: createMemo(() => providers().all), + default: createMemo(() => providers().default), + popular, + connected, + paid, + } +} diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts new file mode 100644 index 00000000000..08c69ea62c9 --- /dev/null +++ b/packages/app/src/i18n/ar.ts @@ -0,0 +1,654 @@ +export const dict = { + "command.category.suggested": "مقترح", + "command.category.view": "عرض", + "command.category.project": "مشروع", + "command.category.provider": "موفر", + "command.category.server": "خادم", + "command.category.session": "جلسة", + "command.category.theme": "سمة", + "command.category.language": "لغة", + "command.category.file": "ملف", + "command.category.terminal": "محطة طرفية", + "command.category.model": "نموذج", + "command.category.mcp": "MCP", + "command.category.agent": "وكيل", + "command.category.permissions": "أذونات", + "command.category.workspace": "مساحة عمل", + "command.category.settings": "إعدادات", + + "theme.scheme.system": "نظام", + "theme.scheme.light": "فاتح", + "theme.scheme.dark": "داكن", + + "command.sidebar.toggle": "تبديل الشريط الجانبي", + "command.project.open": "فتح مشروع", + "command.provider.connect": "اتصال بموفر", + "command.server.switch": "تبديل الخادم", + "command.settings.open": "فتح الإعدادات", + "command.session.previous": "الجلسة السابقة", + "command.session.next": "الجلسة التالية", + "command.session.archive": "أرشفة الجلسة", + + "command.palette": "لوحة الأوامر", + + "command.theme.cycle": "تغيير السمة", + "command.theme.set": "استخدام السمة: {{theme}}", + "command.theme.scheme.cycle": "تغيير مخطط الألوان", + "command.theme.scheme.set": "استخدام مخطط الألوان: {{scheme}}", + + "command.language.cycle": "تغيير اللغة", + "command.language.set": "استخدام اللغة: {{language}}", + + "command.session.new": "جلسة جديدة", + "command.file.open": "فتح ملف", + "command.file.open.description": "البحث في الملفات والأوامر", + "command.terminal.toggle": "تبديل المحطة الطرفية", + "command.review.toggle": "تبديل المراجعة", + "command.terminal.new": "محطة طرفية جديدة", + "command.terminal.new.description": "إنشاء علامة تبويب جديدة للمحطة الطرفية", + "command.steps.toggle": "تبديل الخطوات", + "command.steps.toggle.description": "إظهار أو إخفاء خطوات الرسالة الحالية", + "command.message.previous": "الرسالة السابقة", + "command.message.previous.description": "انتقل إلى رسالة المستخدم السابقة", + "command.message.next": "الرسالة التالية", + "command.message.next.description": "انتقل إلى رسالة المستخدم التالية", + "command.model.choose": "اختيار نموذج", + "command.model.choose.description": "حدد نموذجًا مختلفًا", + "command.mcp.toggle": "تبديل MCPs", + "command.mcp.toggle.description": "تبديل MCPs", + "command.agent.cycle": "تغيير الوكيل", + "command.agent.cycle.description": "التبديل إلى الوكيل التالي", + "command.agent.cycle.reverse": "تغيير الوكيل للخلف", + "command.agent.cycle.reverse.description": "التبديل إلى الوكيل السابق", + "command.model.variant.cycle": "تغيير جهد التفكير", + "command.model.variant.cycle.description": "التبديل إلى مستوى الجهد التالي", + "command.permissions.autoaccept.enable": "قبول التعديلات تلقائيًا", + "command.permissions.autoaccept.disable": "إيقاف قبول التعديلات تلقائيًا", + "command.session.undo": "تراجع", + "command.session.undo.description": "تراجع عن الرسالة الأخيرة", + "command.session.redo": "إعادة", + "command.session.redo.description": "إعادة الرسالة التي تم التراجع عنها", + "command.session.compact": "ضغط الجلسة", + "command.session.compact.description": "تلخيص الجلسة لتقليل حجم السياق", + "command.session.fork": "تشعب من الرسالة", + "command.session.fork.description": "إنشاء جلسة جديدة من رسالة سابقة", + "command.session.share": "مشاركة الجلسة", + "command.session.share.description": "مشاركة هذه الجلسة ونسخ الرابط إلى الحافظة", + "command.session.unshare": "إلغاء مشاركة الجلسة", + "command.session.unshare.description": "إيقاف مشاركة هذه الجلسة", + + "palette.search.placeholder": "البحث في الملفات والأوامر", + "palette.empty": "لا توجد نتائج", + "palette.group.commands": "الأوامر", + "palette.group.files": "الملفات", + + "dialog.provider.search.placeholder": "البحث عن موفرين", + "dialog.provider.empty": "لم يتم العثور على موفرين", + "dialog.provider.group.popular": "شائع", + "dialog.provider.group.other": "آخر", + "dialog.provider.tag.recommended": "موصى به", + "dialog.provider.anthropic.note": "اتصل باستخدام Claude Pro/Max أو مفتاح API", + + "dialog.model.select.title": "تحديد نموذج", + "dialog.model.search.placeholder": "البحث عن نماذج", + "dialog.model.empty": "لا توجد نتائج للنماذج", + "dialog.model.manage": "إدارة النماذج", + "dialog.model.manage.description": "تخصيص النماذج التي تظهر في محدد النماذج.", + + "dialog.model.unpaid.freeModels.title": "نماذج مجانية مقدمة من OpenCode", + "dialog.model.unpaid.addMore.title": "إضافة المزيد من النماذج من موفرين مشهورين", + + "dialog.provider.viewAll": "عرض جميع الموفرين", + + "provider.connect.title": "اتصال {{provider}}", + "provider.connect.title.anthropicProMax": "تسجيل الدخول باستخدام Claude Pro/Max", + "provider.connect.selectMethod": "حدد طريقة تسجيل الدخول لـ {{provider}}.", + "provider.connect.method.apiKey": "مفتاح API", + "provider.connect.status.inProgress": "جارٍ التفويض...", + "provider.connect.status.waiting": "في انتظار التفويض...", + "provider.connect.status.failed": "فشل التفويض: {{error}}", + "provider.connect.apiKey.description": + "أدخل مفتاح واجهة برمجة تطبيقات {{provider}} الخاص بك لتوصيل حسابك واستخدام نماذج {{provider}} في OpenCode.", + "provider.connect.apiKey.label": "مفتاح واجهة برمجة تطبيقات {{provider}}", + "provider.connect.apiKey.placeholder": "مفتاح API", + "provider.connect.apiKey.required": "مفتاح API مطلوب", + "provider.connect.opencodeZen.line1": + "يمنحك OpenCode Zen الوصول إلى مجموعة مختارة من النماذج الموثوقة والمحسنة لوكلاء البرمجة.", + "provider.connect.opencodeZen.line2": + "باستخدام مفتاح API واحد، ستحصل على إمكانية الوصول إلى نماذج مثل Claude و GPT و Gemini و GLM والمزيد.", + "provider.connect.opencodeZen.visit.prefix": "قم بزيارة ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " للحصول على مفتاح API الخاص بك.", + "provider.connect.oauth.code.visit.prefix": "قم بزيارة ", + "provider.connect.oauth.code.visit.link": "هذا الرابط", + "provider.connect.oauth.code.visit.suffix": + " للحصول على رمز التفويض الخاص بك لتوصيل حسابك واستخدام نماذج {{provider}} في OpenCode.", + "provider.connect.oauth.code.label": "رمز تفويض {{method}}", + "provider.connect.oauth.code.placeholder": "رمز التفويض", + "provider.connect.oauth.code.required": "رمز التفويض مطلوب", + "provider.connect.oauth.code.invalid": "رمز التفويض غير صالح", + "provider.connect.oauth.auto.visit.prefix": "قم بزيارة ", + "provider.connect.oauth.auto.visit.link": "هذا الرابط", + "provider.connect.oauth.auto.visit.suffix": + " وأدخل الرمز أدناه لتوصيل حسابك واستخدام نماذج {{provider}} في OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "رمز التأكيد", + "provider.connect.toast.connected.title": "تم توصيل {{provider}}", + "provider.connect.toast.connected.description": "نماذج {{provider}} متاحة الآن للاستخدام.", + + "model.tag.free": "مجاني", + "model.tag.latest": "الأحدث", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "نص", + "model.input.image": "صورة", + "model.input.audio": "صوت", + "model.input.video": "فيديو", + "model.input.pdf": "pdf", + "model.tooltip.allows": "يسمح: {{inputs}}", + "model.tooltip.reasoning.allowed": "يسمح بالاستنتاج", + "model.tooltip.reasoning.none": "بدون استنتاج", + "model.tooltip.context": "حد السياق {{limit}}", + + "common.search.placeholder": "بحث", + "common.goBack": "رجوع", + "common.loading": "جارٍ التحميل", + "common.loading.ellipsis": "...", + "common.cancel": "إلغاء", + "common.submit": "إرسال", + "common.save": "حفظ", + "common.saving": "جارٍ الحفظ...", + "common.default": "افتراضي", + "common.attachment": "مرفق", + + "prompt.placeholder.shell": "أدخل أمر shell...", + "prompt.placeholder.normal": 'اسأل أي شيء... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc للخروج", + + "prompt.example.1": "إصلاح TODO في قاعدة التعليمات البرمجية", + "prompt.example.2": "ما هو المكدس التقني لهذا المشروع؟", + "prompt.example.3": "إصلاح الاختبارات المعطلة", + "prompt.example.4": "اشرح كيف تعمل المصادقة", + "prompt.example.5": "البحث عن وإصلاح الثغرات الأمنية", + "prompt.example.6": "إضافة اختبارات وحدة لخدمة المستخدم", + "prompt.example.7": "إعادة هيكلة هذه الدالة لتكون أكثر قابلية للقراءة", + "prompt.example.8": "ماذا يعني هذا الخطأ؟", + "prompt.example.9": "ساعدني في تصحيح هذه المشكلة", + "prompt.example.10": "توليد وثائق API", + "prompt.example.11": "تحسين استعلامات قاعدة البيانات", + "prompt.example.12": "إضافة التحقق من صحة الإدخال", + "prompt.example.13": "إنشاء مكون جديد لـ...", + "prompt.example.14": "كيف أقوم بنشر هذا المشروع؟", + "prompt.example.15": "مراجعة الكود الخاص بي لأفضل الممارسات", + "prompt.example.16": "إضافة معالجة الأخطاء لهذه الدالة", + "prompt.example.17": "اشرح نمط regex هذا", + "prompt.example.18": "تحويل هذا إلى TypeScript", + "prompt.example.19": "إضافة تسجيل الدخول (logging) في جميع أنحاء قاعدة التعليمات البرمجية", + "prompt.example.20": "ما هي التبعيات القديمة؟", + "prompt.example.21": "ساعدني في كتابة برنامج نصي للهجرة", + "prompt.example.22": "تنفيذ التخزين المؤقت لهذه النقطة النهائية", + "prompt.example.23": "إضافة ترقيم الصفحات إلى هذه القائمة", + "prompt.example.24": "إنشاء أمر CLI لـ...", + "prompt.example.25": "كيف تعمل متغيرات البيئة هنا؟", + + "prompt.popover.emptyResults": "لا توجد نتائج مطابقة", + "prompt.popover.emptyCommands": "لا توجد أوامر مطابقة", + "prompt.dropzone.label": "أفلت الصور أو ملفات PDF هنا", + "prompt.slash.badge.custom": "مخصص", + "prompt.context.active": "نشط", + "prompt.context.includeActiveFile": "تضمين الملف النشط", + "prompt.context.removeActiveFile": "إزالة الملف النشط من السياق", + "prompt.context.removeFile": "إزالة الملف من السياق", + "prompt.action.attachFile": "إرفاق ملف", + "prompt.attachment.remove": "إزالة المرفق", + "prompt.action.send": "إرسال", + "prompt.action.stop": "توقف", + + "prompt.toast.pasteUnsupported.title": "لصق غير مدعوم", + "prompt.toast.pasteUnsupported.description": "يمكن لصق الصور أو ملفات PDF فقط هنا.", + "prompt.toast.modelAgentRequired.title": "حدد وكيلاً ونموذجاً", + "prompt.toast.modelAgentRequired.description": "اختر وكيلاً ونموذجاً قبل إرسال الموجه.", + "prompt.toast.worktreeCreateFailed.title": "فشل إنشاء شجرة العمل", + "prompt.toast.sessionCreateFailed.title": "فشل إنشاء الجلسة", + "prompt.toast.shellSendFailed.title": "فشل إرسال أمر shell", + "prompt.toast.commandSendFailed.title": "فشل إرسال الأمر", + "prompt.toast.promptSendFailed.title": "فشل إرسال الموجه", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} من {{total}} مفعل", + "dialog.mcp.empty": "لم يتم تكوين MCPs", + + "mcp.status.connected": "متصل", + "mcp.status.failed": "فشل", + "mcp.status.needs_auth": "يحتاج إلى مصادقة", + "mcp.status.disabled": "معطل", + + "dialog.fork.empty": "لا توجد رسائل للتفرع منها", + + "dialog.directory.search.placeholder": "البحث في المجلدات", + "dialog.directory.empty": "لم يتم العثور على مجلدات", + + "dialog.server.title": "الخوادم", + "dialog.server.description": "تبديل خادم OpenCode الذي يتصل به هذا التطبيق.", + "dialog.server.search.placeholder": "البحث في الخوادم", + "dialog.server.empty": "لا توجد خوادم بعد", + "dialog.server.add.title": "إضافة خادم", + "dialog.server.add.url": "عنوان URL للخادم", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "تعذر الاتصال بالخادم", + "dialog.server.add.checking": "جارٍ التحقق...", + "dialog.server.add.button": "إضافة", + "dialog.server.default.title": "الخادم الافتراضي", + "dialog.server.default.description": + "الاتصال بهذا الخادم عند بدء تشغيل التطبيق بدلاً من بدء خادم محلي. يتطلب إعادة التشغيل.", + "dialog.server.default.none": "لم يتم تحديد خادم", + "dialog.server.default.set": "تعيين الخادم الحالي كافتراضي", + "dialog.server.default.clear": "مسح", + "dialog.server.action.remove": "إزالة الخادم", + + "dialog.project.edit.title": "تحرير المشروع", + "dialog.project.edit.name": "الاسم", + "dialog.project.edit.icon": "أيقونة", + "dialog.project.edit.icon.alt": "أيقونة المشروع", + "dialog.project.edit.icon.hint": "انقر أو اسحب صورة", + "dialog.project.edit.icon.recommended": "موصى به: 128x128px", + "dialog.project.edit.color": "لون", + "dialog.project.edit.color.select": "اختر لون {{color}}", + + "context.breakdown.title": "تفصيل السياق", + "context.breakdown.note": 'تفصيل تقريبي لرموز الإدخال. يشمل "أخرى" تعريفات الأدوات والنفقات العامة.', + "context.breakdown.system": "النظام", + "context.breakdown.user": "المستخدم", + "context.breakdown.assistant": "المساعد", + "context.breakdown.tool": "استدعاءات الأداة", + "context.breakdown.other": "أخرى", + + "context.systemPrompt.title": "موجه النظام", + "context.rawMessages.title": "الرسائل الخام", + + "context.stats.session": "جلسة", + "context.stats.messages": "رسائل", + "context.stats.provider": "موفر", + "context.stats.model": "نموذج", + "context.stats.limit": "حد السياق", + "context.stats.totalTokens": "إجمالي الرموز", + "context.stats.usage": "استخدام", + "context.stats.inputTokens": "رموز الإدخال", + "context.stats.outputTokens": "رموز الإخراج", + "context.stats.reasoningTokens": "رموز الاستنتاج", + "context.stats.cacheTokens": "رموز التخزين المؤقت (قراءة/كتابة)", + "context.stats.userMessages": "رسائل المستخدم", + "context.stats.assistantMessages": "رسائل المساعد", + "context.stats.totalCost": "التكلفة الإجمالية", + "context.stats.sessionCreated": "تم إنشاء الجلسة", + "context.stats.lastActivity": "آخر نشاط", + + "context.usage.tokens": "رموز", + "context.usage.usage": "استخدام", + "context.usage.cost": "تكلفة", + "context.usage.clickToView": "انقر لعرض السياق", + "context.usage.view": "عرض استخدام السياق", + + "language.en": "الإنجليزية", + "language.zh": "الصينية (المبسطة)", + "language.zht": "الصينية (التقليدية)", + "language.ko": "الكورية", + "language.de": "الألمانية", + "language.es": "الإسبانية", + "language.fr": "الفرنسية", + "language.ja": "اليابانية", + "language.da": "الدانماركية", + "language.ru": "الروسية", + "language.pl": "البولندية", + "language.ar": "العربية", + "language.no": "النرويجية", + "language.br": "البرتغالية (البرازيل)", + + "toast.language.title": "لغة", + "toast.language.description": "تم التبديل إلى {{language}}", + + "toast.theme.title": "تم تبديل السمة", + "toast.scheme.title": "مخطط الألوان", + + "toast.permissions.autoaccept.on.title": "قبول التعديلات تلقائيًا", + "toast.permissions.autoaccept.on.description": "سيتم الموافقة تلقائيًا على أذونات التحرير والكتابة", + "toast.permissions.autoaccept.off.title": "توقف قبول التعديلات تلقائيًا", + "toast.permissions.autoaccept.off.description": "ستتطلب أذونات التحرير والكتابة موافقة", + + "toast.model.none.title": "لم يتم تحديد نموذج", + "toast.model.none.description": "قم بتوصيل موفر لتلخيص هذه الجلسة", + + "toast.file.loadFailed.title": "فشل تحميل الملف", + + "toast.session.share.copyFailed.title": "فشل نسخ عنوان URL إلى الحافظة", + "toast.session.share.success.title": "تمت مشاركة الجلسة", + "toast.session.share.success.description": "تم نسخ عنوان URL للمشاركة إلى الحافظة!", + "toast.session.share.failed.title": "فشل مشاركة الجلسة", + "toast.session.share.failed.description": "حدث خطأ أثناء مشاركة الجلسة", + + "toast.session.unshare.success.title": "تم إلغاء مشاركة الجلسة", + "toast.session.unshare.success.description": "تم إلغاء مشاركة الجلسة بنجاح!", + "toast.session.unshare.failed.title": "فشل إلغاء مشاركة الجلسة", + "toast.session.unshare.failed.description": "حدث خطأ أثناء إلغاء مشاركة الجلسة", + + "toast.session.listFailed.title": "فشل تحميل الجلسات لـ {{project}}", + + "toast.update.title": "تحديث متاح", + "toast.update.description": "نسخة جديدة من OpenCode ({{version}}) متاحة الآن للتثبيت.", + "toast.update.action.installRestart": "تثبيت وإعادة تشغيل", + "toast.update.action.notYet": "ليس الآن", + + "error.page.title": "حدث خطأ ما", + "error.page.description": "حدث خطأ أثناء تحميل التطبيق.", + "error.page.details.label": "تفاصيل الخطأ", + "error.page.action.restart": "إعادة تشغيل", + "error.page.action.checking": "جارٍ التحقق...", + "error.page.action.checkUpdates": "التحقق من وجود تحديثات", + "error.page.action.updateTo": "تحديث إلى {{version}}", + "error.page.report.prefix": "يرجى الإبلاغ عن هذا الخطأ لفريق OpenCode", + "error.page.report.discord": "على Discord", + "error.page.version": "الإصدار: {{version}}", + + "error.dev.rootNotFound": + "لم يتم العثور على العنصر الجذري. هل نسيت إضافته إلى index.html؟ أو ربما تمت كتابة سمة id بشكل خاطئ؟", + + "error.globalSync.connectFailed": "تعذر الاتصال بالخادم. هل هناك خادم يعمل في `{{url}}`؟", + + "error.chain.unknown": "خطأ غير معروف", + "error.chain.causedBy": "بسبب:", + "error.chain.apiError": "خطأ API", + "error.chain.status": "الحالة: {{status}}", + "error.chain.retryable": "قابل لإعادة المحاولة: {{retryable}}", + "error.chain.responseBody": "نص الاستجابة:\n{{body}}", + "error.chain.didYouMean": "هل كنت تعني: {{suggestions}}", + "error.chain.modelNotFound": "النموذج غير موجود: {{provider}}/{{model}}", + "error.chain.checkConfig": "تحقق من أسماء الموفر/النموذج في التكوين (opencode.json)", + "error.chain.mcpFailed": 'فشل خادم MCP "{{name}}". لاحظ أن OpenCode لا يدعم مصادقة MCP بعد.', + "error.chain.providerAuthFailed": "فشلت مصادقة الموفر ({{provider}}): {{message}}", + "error.chain.providerInitFailed": 'فشل تهيئة الموفر "{{provider}}". تحقق من بيانات الاعتماد والتكوين.', + "error.chain.configJsonInvalid": "ملف التكوين في {{path}} ليس JSON(C) صالحًا", + "error.chain.configJsonInvalidWithMessage": "ملف التكوين في {{path}} ليس JSON(C) صالحًا: {{message}}", + "error.chain.configDirectoryTypo": + 'الدليل "{{dir}}" في {{path}} غير صالح. أعد تسمية الدليل إلى "{{suggestion}}" أو قم بإزالته. هذا خطأ مطبعي شائع.', + "error.chain.configFrontmatterError": "فشل تحليل frontmatter في {{path}}:\n{{message}}", + "error.chain.configInvalid": "ملف التكوين في {{path}} غير صالح", + "error.chain.configInvalidWithMessage": "ملف التكوين في {{path}} غير صالح: {{message}}", + + "notification.permission.title": "مطلوب إذن", + "notification.permission.description": "{{sessionTitle}} في {{projectName}} يحتاج إلى إذن", + "notification.question.title": "سؤال", + "notification.question.description": "{{sessionTitle}} في {{projectName}} لديه سؤال", + "notification.action.goToSession": "انتقل إلى الجلسة", + + "notification.session.responseReady.title": "الاستجابة جاهزة", + "notification.session.error.title": "خطأ في الجلسة", + "notification.session.error.fallbackDescription": "حدث خطأ", + + "home.recentProjects": "المشاريع الحديثة", + "home.empty.title": "لا توجد مشاريع حديثة", + "home.empty.description": "ابدأ بفتح مشروع محلي", + + "session.tab.session": "جلسة", + "session.tab.review": "مراجعة", + "session.tab.context": "سياق", + "session.panel.reviewAndFiles": "المراجعة والملفات", + "session.review.filesChanged": "تم تغيير {{count}} ملفات", + "session.review.loadingChanges": "جارٍ تحميل التغييرات...", + "session.review.empty": "لا توجد تغييرات في هذه الجلسة بعد", + "session.messages.renderEarlier": "عرض الرسائل السابقة", + "session.messages.loadingEarlier": "جارٍ تحميل الرسائل السابقة...", + "session.messages.loadEarlier": "تحميل الرسائل السابقة", + "session.messages.loading": "جارٍ تحميل الرسائل...", + "session.messages.jumpToLatest": "الانتقال إلى الأحدث", + + "session.context.addToContext": "إضافة {{selection}} إلى السياق", + + "session.new.worktree.main": "الفرع الرئيسي", + "session.new.worktree.mainWithBranch": "الفرع الرئيسي ({{branch}})", + "session.new.worktree.create": "إنشاء شجرة عمل جديدة", + "session.new.lastModified": "آخر تعديل", + + "session.header.search.placeholder": "بحث {{project}}", + "session.header.searchFiles": "بحث عن الملفات", + + "session.share.popover.title": "نشر على الويب", + "session.share.popover.description.shared": "هذه الجلسة عامة على الويب. يمكن لأي شخص لديه الرابط الوصول إليها.", + "session.share.popover.description.unshared": "شارك الجلسة علنًا على الويب. ستكون متاحة لأي شخص لديه الرابط.", + "session.share.action.share": "مشاركة", + "session.share.action.publish": "نشر", + "session.share.action.publishing": "جارٍ النشر...", + "session.share.action.unpublish": "إلغاء النشر", + "session.share.action.unpublishing": "جارٍ إلغاء النشر...", + "session.share.action.view": "عرض", + "session.share.copy.copied": "تم النسخ", + "session.share.copy.copyLink": "نسخ الرابط", + + "lsp.tooltip.none": "لا توجد خوادم LSP", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "جارٍ تحميل الموجه...", + "terminal.loading": "جارٍ تحميل المحطة الطرفية...", + "terminal.title": "محطة طرفية", + "terminal.title.numbered": "محطة طرفية {{number}}", + "terminal.close": "إغلاق المحطة الطرفية", + "terminal.connectionLost.title": "فقد الاتصال", + "terminal.connectionLost.description": "انقطع اتصال المحطة الطرفية. يمكن أن يحدث هذا عند إعادة تشغيل الخادم.", + + "common.closeTab": "إغلاق علامة التبويب", + "common.dismiss": "رفض", + "common.requestFailed": "فشل الطلب", + "common.moreOptions": "مزيد من الخيارات", + "common.learnMore": "اعرف المزيد", + "common.rename": "إعادة تسمية", + "common.reset": "إعادة تعيين", + "common.archive": "أرشفة", + "common.delete": "حذف", + "common.close": "إغلاق", + "common.edit": "تحرير", + "common.loadMore": "تحميل المزيد", + "common.key.esc": "ESC", + + "sidebar.menu.toggle": "تبديل القائمة", + "sidebar.nav.projectsAndSessions": "المشاريع والجلسات", + "sidebar.settings": "الإعدادات", + "sidebar.help": "مساعدة", + "sidebar.workspaces.enable": "تمكين مساحات العمل", + "sidebar.workspaces.disable": "تعطيل مساحات العمل", + "sidebar.gettingStarted.title": "البدء", + "sidebar.gettingStarted.line1": "يتضمن OpenCode نماذج مجانية حتى تتمكن من البدء فورًا.", + "sidebar.gettingStarted.line2": "قم بتوصيل أي موفر لاستخدام النماذج، بما في ذلك Claude و GPT و Gemini وما إلى ذلك.", + "sidebar.project.recentSessions": "الجلسات الحديثة", + "sidebar.project.viewAllSessions": "عرض جميع الجلسات", + + "settings.section.desktop": "سطح المكتب", + "settings.tab.general": "عام", + "settings.tab.shortcuts": "اختصارات", + + "settings.general.section.appearance": "المظهر", + "settings.general.section.notifications": "إشعارات النظام", + "settings.general.section.sounds": "المؤثرات الصوتية", + + "settings.general.row.language.title": "اللغة", + "settings.general.row.language.description": "تغيير لغة العرض لـ OpenCode", + "settings.general.row.appearance.title": "المظهر", + "settings.general.row.appearance.description": "تخصيص كيفية ظهور OpenCode على جهازك", + "settings.general.row.theme.title": "السمة", + "settings.general.row.theme.description": "تخصيص سمة OpenCode.", + "settings.general.row.font.title": "الخط", + "settings.general.row.font.description": "تخصيص الخط الأحادي المستخدم في كتل التعليمات البرمجية", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "sound.option.alert01": "تنبيه 01", + "sound.option.alert02": "تنبيه 02", + "sound.option.alert03": "تنبيه 03", + "sound.option.alert04": "تنبيه 04", + "sound.option.alert05": "تنبيه 05", + "sound.option.alert06": "تنبيه 06", + "sound.option.alert07": "تنبيه 07", + "sound.option.alert08": "تنبيه 08", + "sound.option.alert09": "تنبيه 09", + "sound.option.alert10": "تنبيه 10", + "sound.option.bipbop01": "بيب بوب 01", + "sound.option.bipbop02": "بيب بوب 02", + "sound.option.bipbop03": "بيب بوب 03", + "sound.option.bipbop04": "بيب بوب 04", + "sound.option.bipbop05": "بيب بوب 05", + "sound.option.bipbop06": "بيب بوب 06", + "sound.option.bipbop07": "بيب بوب 07", + "sound.option.bipbop08": "بيب بوب 08", + "sound.option.bipbop09": "بيب بوب 09", + "sound.option.bipbop10": "بيب بوب 10", + "sound.option.staplebops01": "ستابل بوبس 01", + "sound.option.staplebops02": "ستابل بوبس 02", + "sound.option.staplebops03": "ستابل بوبس 03", + "sound.option.staplebops04": "ستابل بوبس 04", + "sound.option.staplebops05": "ستابل بوبس 05", + "sound.option.staplebops06": "ستابل بوبس 06", + "sound.option.staplebops07": "ستابل بوبس 07", + "sound.option.nope01": "كلا 01", + "sound.option.nope02": "كلا 02", + "sound.option.nope03": "كلا 03", + "sound.option.nope04": "كلا 04", + "sound.option.nope05": "كلا 05", + "sound.option.nope06": "كلا 06", + "sound.option.nope07": "كلا 07", + "sound.option.nope08": "كلا 08", + "sound.option.nope09": "كلا 09", + "sound.option.nope10": "كلا 10", + "sound.option.nope11": "كلا 11", + "sound.option.nope12": "كلا 12", + "sound.option.yup01": "نعم 01", + "sound.option.yup02": "نعم 02", + "sound.option.yup03": "نعم 03", + "sound.option.yup04": "نعم 04", + "sound.option.yup05": "نعم 05", + "sound.option.yup06": "نعم 06", + + "settings.general.notifications.agent.title": "وكيل", + "settings.general.notifications.agent.description": "عرض إشعار النظام عندما يكتمل الوكيل أو يحتاج إلى اهتمام", + "settings.general.notifications.permissions.title": "أذونات", + "settings.general.notifications.permissions.description": "عرض إشعار النظام عند الحاجة إلى إذن", + "settings.general.notifications.errors.title": "أخطاء", + "settings.general.notifications.errors.description": "عرض إشعار النظام عند حدوث خطأ", + + "settings.general.sounds.agent.title": "وكيل", + "settings.general.sounds.agent.description": "تشغيل صوت عندما يكتمل الوكيل أو يحتاج إلى اهتمام", + "settings.general.sounds.permissions.title": "أذونات", + "settings.general.sounds.permissions.description": "تشغيل صوت عند الحاجة إلى إذن", + "settings.general.sounds.errors.title": "أخطاء", + "settings.general.sounds.errors.description": "تشغيل صوت عند حدوث خطأ", + + "settings.shortcuts.title": "اختصارات لوحة المفاتيح", + "settings.shortcuts.reset.button": "إعادة التعيين إلى الافتراضيات", + "settings.shortcuts.reset.toast.title": "تم إعادة تعيين الاختصارات", + "settings.shortcuts.reset.toast.description": "تم إعادة تعيين اختصارات لوحة المفاتيح إلى الافتراضيات.", + "settings.shortcuts.conflict.title": "الاختصار قيد الاستخدام بالفعل", + "settings.shortcuts.conflict.description": "{{keybind}} معين بالفعل لـ {{titles}}.", + "settings.shortcuts.unassigned": "غير معين", + "settings.shortcuts.pressKeys": "اضغط على المفاتيح", + "settings.shortcuts.search.placeholder": "البحث في الاختصارات", + "settings.shortcuts.search.empty": "لم يتم العثور على اختصارات", + + "settings.shortcuts.group.general": "عام", + "settings.shortcuts.group.session": "جلسة", + "settings.shortcuts.group.navigation": "تصفح", + "settings.shortcuts.group.modelAndAgent": "النموذج والوكيل", + "settings.shortcuts.group.terminal": "المحطة الطرفية", + "settings.shortcuts.group.prompt": "موجه", + + "settings.providers.title": "الموفرون", + "settings.providers.description": "ستكون إعدادات الموفر قابلة للتكوين هنا.", + "settings.models.title": "النماذج", + "settings.models.description": "ستكون إعدادات النموذج قابلة للتكوين هنا.", + "settings.agents.title": "الوكلاء", + "settings.agents.description": "ستكون إعدادات الوكيل قابلة للتكوين هنا.", + "settings.commands.title": "الأوامر", + "settings.commands.description": "ستكون إعدادات الأمر قابلة للتكوين هنا.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "ستكون إعدادات MCP قابلة للتكوين هنا.", + + "settings.permissions.title": "الأذونات", + "settings.permissions.description": "تحكم في الأدوات التي يمكن للخادم استخدامها بشكل افتراضي.", + "settings.permissions.section.tools": "الأدوات", + "settings.permissions.toast.updateFailed.title": "فشل تحديث الأذونات", + + "settings.permissions.action.allow": "سماح", + "settings.permissions.action.ask": "سؤال", + "settings.permissions.action.deny": "رفض", + + "settings.permissions.tool.read.title": "قراءة", + "settings.permissions.tool.read.description": "قراءة ملف (يطابق مسار الملف)", + "settings.permissions.tool.edit.title": "تحرير", + "settings.permissions.tool.edit.description": + "تعديل الملفات، بما في ذلك التحرير والكتابة والتصحيحات والتحرير المتعدد", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "مطابقة الملفات باستخدام أنماط glob", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "البحث في محتويات الملف باستخدام التعبيرات العادية", + "settings.permissions.tool.list.title": "قائمة", + "settings.permissions.tool.list.description": "سرد الملفات داخل دليل", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "تشغيل أوامر shell", + "settings.permissions.tool.task.title": "Task", + "settings.permissions.tool.task.description": "تشغيل الوكلاء الفرعيين", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "تحميل مهارة بالاسم", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "تشغيل استعلامات خادم اللغة", + "settings.permissions.tool.todoread.title": "قراءة المهام", + "settings.permissions.tool.todoread.description": "قراءة قائمة المهام", + "settings.permissions.tool.todowrite.title": "كتابة المهام", + "settings.permissions.tool.todowrite.description": "تحديث قائمة المهام", + "settings.permissions.tool.webfetch.title": "جلب الويب", + "settings.permissions.tool.webfetch.description": "جلب محتوى من عنوان URL", + "settings.permissions.tool.websearch.title": "بحث الويب", + "settings.permissions.tool.websearch.description": "البحث في الويب", + "settings.permissions.tool.codesearch.title": "بحث الكود", + "settings.permissions.tool.codesearch.description": "البحث عن كود على الويب", + "settings.permissions.tool.external_directory.title": "دليل خارجي", + "settings.permissions.tool.external_directory.description": "الوصول إلى الملفات خارج دليل المشروع", + "settings.permissions.tool.doom_loop.title": "حلقة الموت", + "settings.permissions.tool.doom_loop.description": "اكتشاف استدعاءات الأدوات المتكررة بمدخلات متطابقة", + + "session.delete.failed.title": "فشل حذف الجلسة", + "session.delete.title": "حذف الجلسة", + "session.delete.confirm": 'حذف الجلسة "{{name}}"؟', + "session.delete.button": "حذف الجلسة", + + "workspace.new": "مساحة عمل جديدة", + "workspace.type.local": "محلي", + "workspace.type.sandbox": "صندوق رمل", + "workspace.create.failed.title": "فشل إنشاء مساحة العمل", + "workspace.delete.failed.title": "فشل حذف مساحة العمل", + "workspace.resetting.title": "إعادة تعيين مساحة العمل", + "workspace.resetting.description": "قد يستغرق هذا دقيقة.", + "workspace.reset.failed.title": "فشل إعادة تعيين مساحة العمل", + "workspace.reset.success.title": "تمت إعادة تعيين مساحة العمل", + "workspace.reset.success.description": "مساحة العمل تطابق الآن الفرع الافتراضي.", + "workspace.status.checking": "التحقق من التغييرات غير المدمجة...", + "workspace.status.error": "تعذر التحقق من حالة git.", + "workspace.status.clean": "لم يتم اكتشاف تغييرات غير مدمجة.", + "workspace.status.dirty": "تم اكتشاف تغييرات غير مدمجة في مساحة العمل هذه.", + "workspace.delete.title": "حذف مساحة العمل", + "workspace.delete.confirm": 'حذف مساحة العمل "{{name}}"؟', + "workspace.delete.button": "حذف مساحة العمل", + "workspace.reset.title": "إعادة تعيين مساحة العمل", + "workspace.reset.confirm": 'إعادة تعيين مساحة العمل "{{name}}"؟', + "workspace.reset.button": "إعادة تعيين مساحة العمل", + "workspace.reset.archived.none": "لن تتم أرشفة أي جلسات نشطة.", + "workspace.reset.archived.one": "ستتم أرشفة جلسة واحدة.", + "workspace.reset.archived.many": "ستتم أرشفة {{count}} جلسات.", + "workspace.reset.note": "سيؤدي هذا إلى إعادة تعيين مساحة العمل لتتطابق مع الفرع الافتراضي.", +} diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts new file mode 100644 index 00000000000..af9a71b16fd --- /dev/null +++ b/packages/app/src/i18n/br.ts @@ -0,0 +1,665 @@ +export const dict = { + "command.category.suggested": "Sugerido", + "command.category.view": "Visualizar", + "command.category.project": "Projeto", + "command.category.provider": "Provedor", + "command.category.server": "Servidor", + "command.category.session": "Sessão", + "command.category.theme": "Tema", + "command.category.language": "Idioma", + "command.category.file": "Arquivo", + "command.category.terminal": "Terminal", + "command.category.model": "Modelo", + "command.category.mcp": "MCP", + "command.category.agent": "Agente", + "command.category.permissions": "Permissões", + "command.category.workspace": "Espaço de trabalho", + "command.category.settings": "Configurações", + + "theme.scheme.system": "Sistema", + "theme.scheme.light": "Claro", + "theme.scheme.dark": "Escuro", + + "command.sidebar.toggle": "Alternar barra lateral", + "command.project.open": "Abrir projeto", + "command.provider.connect": "Conectar provedor", + "command.server.switch": "Trocar servidor", + "command.settings.open": "Abrir configurações", + "command.session.previous": "Sessão anterior", + "command.session.next": "Próxima sessão", + "command.session.archive": "Arquivar sessão", + + "command.palette": "Paleta de comandos", + + "command.theme.cycle": "Alternar tema", + "command.theme.set": "Usar tema: {{theme}}", + "command.theme.scheme.cycle": "Alternar esquema de cores", + "command.theme.scheme.set": "Usar esquema de cores: {{scheme}}", + + "command.language.cycle": "Alternar idioma", + "command.language.set": "Usar idioma: {{language}}", + + "command.session.new": "Nova sessão", + "command.file.open": "Abrir arquivo", + "command.file.open.description": "Buscar arquivos e comandos", + "command.terminal.toggle": "Alternar terminal", + "command.review.toggle": "Alternar revisão", + "command.terminal.new": "Novo terminal", + "command.terminal.new.description": "Criar uma nova aba de terminal", + "command.steps.toggle": "Alternar passos", + "command.steps.toggle.description": "Mostrar ou ocultar passos da mensagem atual", + "command.message.previous": "Mensagem anterior", + "command.message.previous.description": "Ir para a mensagem de usuário anterior", + "command.message.next": "Próxima mensagem", + "command.message.next.description": "Ir para a próxima mensagem de usuário", + "command.model.choose": "Escolher modelo", + "command.model.choose.description": "Selecionar um modelo diferente", + "command.mcp.toggle": "Alternar MCPs", + "command.mcp.toggle.description": "Alternar MCPs", + "command.agent.cycle": "Alternar agente", + "command.agent.cycle.description": "Mudar para o próximo agente", + "command.agent.cycle.reverse": "Alternar agente (reverso)", + "command.agent.cycle.reverse.description": "Mudar para o agente anterior", + "command.model.variant.cycle": "Alternar nível de raciocínio", + "command.model.variant.cycle.description": "Mudar para o próximo nível de esforço", + "command.permissions.autoaccept.enable": "Aceitar edições automaticamente", + "command.permissions.autoaccept.disable": "Parar de aceitar edições automaticamente", + "command.session.undo": "Desfazer", + "command.session.undo.description": "Desfazer a última mensagem", + "command.session.redo": "Refazer", + "command.session.redo.description": "Refazer a última mensagem desfeita", + "command.session.compact": "Compactar sessão", + "command.session.compact.description": "Resumir a sessão para reduzir o tamanho do contexto", + "command.session.fork": "Bifurcar da mensagem", + "command.session.fork.description": "Criar uma nova sessão a partir de uma mensagem anterior", + "command.session.share": "Compartilhar sessão", + "command.session.share.description": "Compartilhar esta sessão e copiar a URL para a área de transferência", + "command.session.unshare": "Parar de compartilhar sessão", + "command.session.unshare.description": "Parar de compartilhar esta sessão", + + "palette.search.placeholder": "Buscar arquivos e comandos", + "palette.empty": "Nenhum resultado encontrado", + "palette.group.commands": "Comandos", + "palette.group.files": "Arquivos", + + "dialog.provider.search.placeholder": "Buscar provedores", + "dialog.provider.empty": "Nenhum provedor encontrado", + "dialog.provider.group.popular": "Popular", + "dialog.provider.group.other": "Outro", + "dialog.provider.tag.recommended": "Recomendado", + "dialog.provider.anthropic.note": "Conectar com Claude Pro/Max ou chave de API", + + "dialog.model.select.title": "Selecionar modelo", + "dialog.model.search.placeholder": "Buscar modelos", + "dialog.model.empty": "Nenhum resultado de modelo", + "dialog.model.manage": "Gerenciar modelos", + "dialog.model.manage.description": "Personalizar quais modelos aparecem no seletor de modelos.", + + "dialog.model.unpaid.freeModels.title": "Modelos gratuitos fornecidos pelo OpenCode", + "dialog.model.unpaid.addMore.title": "Adicionar mais modelos de provedores populares", + + "dialog.provider.viewAll": "Ver todos os provedores", + + "provider.connect.title": "Conectar {{provider}}", + "provider.connect.title.anthropicProMax": "Entrar com Claude Pro/Max", + "provider.connect.selectMethod": "Selecionar método de login para {{provider}}.", + "provider.connect.method.apiKey": "Chave de API", + "provider.connect.status.inProgress": "Autorização em andamento...", + "provider.connect.status.waiting": "Aguardando autorização...", + "provider.connect.status.failed": "Autorização falhou: {{error}}", + "provider.connect.apiKey.description": + "Digite sua chave de API do {{provider}} para conectar sua conta e usar modelos do {{provider}} no OpenCode.", + "provider.connect.apiKey.label": "Chave de API do {{provider}}", + "provider.connect.apiKey.placeholder": "Chave de API", + "provider.connect.apiKey.required": "A chave de API é obrigatória", + "provider.connect.opencodeZen.line1": + "OpenCode Zen oferece acesso a um conjunto selecionado de modelos confiáveis otimizados para agentes de código.", + "provider.connect.opencodeZen.line2": + "Com uma única chave de API você terá acesso a modelos como Claude, GPT, Gemini, GLM e mais.", + "provider.connect.opencodeZen.visit.prefix": "Visite ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " para obter sua chave de API.", + "provider.connect.oauth.code.visit.prefix": "Visite ", + "provider.connect.oauth.code.visit.link": "este link", + "provider.connect.oauth.code.visit.suffix": + " para obter seu código de autorização e conectar sua conta para usar modelos do {{provider}} no OpenCode.", + "provider.connect.oauth.code.label": "Código de autorização {{method}}", + "provider.connect.oauth.code.placeholder": "Código de autorização", + "provider.connect.oauth.code.required": "O código de autorização é obrigatório", + "provider.connect.oauth.code.invalid": "Código de autorização inválido", + "provider.connect.oauth.auto.visit.prefix": "Visite ", + "provider.connect.oauth.auto.visit.link": "este link", + "provider.connect.oauth.auto.visit.suffix": + " e digite o código abaixo para conectar sua conta e usar modelos do {{provider}} no OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Código de confirmação", + "provider.connect.toast.connected.title": "{{provider}} conectado", + "provider.connect.toast.connected.description": "Modelos do {{provider}} agora estão disponíveis para uso.", + + "model.tag.free": "Grátis", + "model.tag.latest": "Mais recente", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "texto", + "model.input.image": "imagem", + "model.input.audio": "áudio", + "model.input.video": "vídeo", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Permite: {{inputs}}", + "model.tooltip.reasoning.allowed": "Permite raciocínio", + "model.tooltip.reasoning.none": "Sem raciocínio", + "model.tooltip.context": "Limite de contexto {{limit}}", + + "common.search.placeholder": "Buscar", + "common.goBack": "Voltar", + "common.loading": "Carregando", + "common.loading.ellipsis": "...", + "common.cancel": "Cancelar", + "common.submit": "Enviar", + "common.save": "Salvar", + "common.saving": "Salvando...", + "common.default": "Padrão", + "common.attachment": "anexo", + + "prompt.placeholder.shell": "Digite comando do shell...", + "prompt.placeholder.normal": 'Pergunte qualquer coisa... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc para sair", + + "prompt.example.1": "Corrigir um TODO no código", + "prompt.example.2": "Qual é a stack tecnológica deste projeto?", + "prompt.example.3": "Corrigir testes quebrados", + "prompt.example.4": "Explicar como funciona a autenticação", + "prompt.example.5": "Encontrar e corrigir vulnerabilidades de segurança", + "prompt.example.6": "Adicionar testes unitários para o serviço de usuário", + "prompt.example.7": "Refatorar esta função para melhor legibilidade", + "prompt.example.8": "O que significa este erro?", + "prompt.example.9": "Me ajude a depurar este problema", + "prompt.example.10": "Gerar documentação da API", + "prompt.example.11": "Otimizar consultas ao banco de dados", + "prompt.example.12": "Adicionar validação de entrada", + "prompt.example.13": "Criar um novo componente para...", + "prompt.example.14": "Como faço o deploy deste projeto?", + "prompt.example.15": "Revisar meu código para boas práticas", + "prompt.example.16": "Adicionar tratamento de erros a esta função", + "prompt.example.17": "Explicar este padrão regex", + "prompt.example.18": "Converter isto para TypeScript", + "prompt.example.19": "Adicionar logging em todo o código", + "prompt.example.20": "Quais dependências estão desatualizadas?", + "prompt.example.21": "Me ajude a escrever um script de migração", + "prompt.example.22": "Implementar cache para este endpoint", + "prompt.example.23": "Adicionar paginação a esta lista", + "prompt.example.24": "Criar um comando CLI para...", + "prompt.example.25": "Como funcionam as variáveis de ambiente aqui?", + + "prompt.popover.emptyResults": "Nenhum resultado correspondente", + "prompt.popover.emptyCommands": "Nenhum comando correspondente", + "prompt.dropzone.label": "Solte imagens ou PDFs aqui", + "prompt.slash.badge.custom": "personalizado", + "prompt.context.active": "ativo", + "prompt.context.includeActiveFile": "Incluir arquivo ativo", + "prompt.context.removeActiveFile": "Remover arquivo ativo do contexto", + "prompt.context.removeFile": "Remover arquivo do contexto", + "prompt.action.attachFile": "Anexar arquivo", + "prompt.attachment.remove": "Remover anexo", + "prompt.action.send": "Enviar", + "prompt.action.stop": "Parar", + + "prompt.toast.pasteUnsupported.title": "Colagem não suportada", + "prompt.toast.pasteUnsupported.description": "Somente imagens ou PDFs podem ser colados aqui.", + "prompt.toast.modelAgentRequired.title": "Selecione um agente e modelo", + "prompt.toast.modelAgentRequired.description": "Escolha um agente e modelo antes de enviar um prompt.", + "prompt.toast.worktreeCreateFailed.title": "Falha ao criar worktree", + "prompt.toast.sessionCreateFailed.title": "Falha ao criar sessão", + "prompt.toast.shellSendFailed.title": "Falha ao enviar comando shell", + "prompt.toast.commandSendFailed.title": "Falha ao enviar comando", + "prompt.toast.promptSendFailed.title": "Falha ao enviar prompt", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} de {{total}} habilitados", + "dialog.mcp.empty": "Nenhum MCP configurado", + + "mcp.status.connected": "conectado", + "mcp.status.failed": "falhou", + "mcp.status.needs_auth": "precisa de autenticação", + "mcp.status.disabled": "desabilitado", + + "dialog.fork.empty": "Nenhuma mensagem para bifurcar", + + "dialog.directory.search.placeholder": "Buscar pastas", + "dialog.directory.empty": "Nenhuma pasta encontrada", + + "dialog.server.title": "Servidores", + "dialog.server.description": "Trocar para qual servidor OpenCode este aplicativo se conecta.", + "dialog.server.search.placeholder": "Buscar servidores", + "dialog.server.empty": "Nenhum servidor ainda", + "dialog.server.add.title": "Adicionar um servidor", + "dialog.server.add.url": "URL do servidor", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Não foi possível conectar ao servidor", + "dialog.server.add.checking": "Verificando...", + "dialog.server.add.button": "Adicionar", + "dialog.server.default.title": "Servidor padrão", + "dialog.server.default.description": + "Conectar a este servidor na inicialização do aplicativo ao invés de iniciar um servidor local. Requer reinicialização.", + "dialog.server.default.none": "Nenhum servidor selecionado", + "dialog.server.default.set": "Definir servidor atual como padrão", + "dialog.server.default.clear": "Limpar", + "dialog.server.action.remove": "Remover servidor", + + "dialog.project.edit.title": "Editar projeto", + "dialog.project.edit.name": "Nome", + "dialog.project.edit.icon": "Ícone", + "dialog.project.edit.icon.alt": "Ícone do projeto", + "dialog.project.edit.icon.hint": "Clique ou arraste uma imagem", + "dialog.project.edit.icon.recommended": "Recomendado: 128x128px", + "dialog.project.edit.color": "Cor", + "dialog.project.edit.color.select": "Selecionar cor {{color}}", + "dialog.project.edit.worktree.startup": "Script de inicialização do espaço de trabalho", + "dialog.project.edit.worktree.startup.description": "Executa após criar um novo espaço de trabalho (worktree).", + "dialog.project.edit.worktree.startup.placeholder": "ex: bun install", + + "context.breakdown.title": "Detalhamento do Contexto", + "context.breakdown.note": + 'Detalhamento aproximado dos tokens de entrada. "Outros" inclui definições de ferramentas e overhead.', + "context.breakdown.system": "Sistema", + "context.breakdown.user": "Usuário", + "context.breakdown.assistant": "Assistente", + "context.breakdown.tool": "Chamadas de Ferramentas", + "context.breakdown.other": "Outros", + + "context.systemPrompt.title": "Prompt do Sistema", + "context.rawMessages.title": "Mensagens brutas", + + "context.stats.session": "Sessão", + "context.stats.messages": "Mensagens", + "context.stats.provider": "Provedor", + "context.stats.model": "Modelo", + "context.stats.limit": "Limite de Contexto", + "context.stats.totalTokens": "Total de Tokens", + "context.stats.usage": "Uso", + "context.stats.inputTokens": "Tokens de Entrada", + "context.stats.outputTokens": "Tokens de Saída", + "context.stats.reasoningTokens": "Tokens de Raciocínio", + "context.stats.cacheTokens": "Tokens de Cache (leitura/escrita)", + "context.stats.userMessages": "Mensagens de Usuário", + "context.stats.assistantMessages": "Mensagens do Assistente", + "context.stats.totalCost": "Custo Total", + "context.stats.sessionCreated": "Sessão Criada", + "context.stats.lastActivity": "Última Atividade", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Uso", + "context.usage.cost": "Custo", + "context.usage.clickToView": "Clique para ver o contexto", + "context.usage.view": "Ver uso do contexto", + + "language.en": "Inglês", + "language.zh": "Chinês (Simplificado)", + "language.zht": "Chinês (Tradicional)", + "language.ko": "Coreano", + "language.de": "Alemão", + "language.es": "Espanhol", + "language.fr": "Francês", + "language.ja": "Japonês", + "language.da": "Dinamarquês", + "language.ru": "Russo", + "language.pl": "Polonês", + "language.ar": "Árabe", + "language.no": "Norueguês", + "language.br": "Português (Brasil)", + + "toast.language.title": "Idioma", + "toast.language.description": "Alterado para {{language}}", + + "toast.theme.title": "Tema alterado", + "toast.scheme.title": "Esquema de cores", + + "toast.permissions.autoaccept.on.title": "Aceitando edições automaticamente", + "toast.permissions.autoaccept.on.description": "Permissões de edição e escrita serão aprovadas automaticamente", + "toast.permissions.autoaccept.off.title": "Parou de aceitar edições automaticamente", + "toast.permissions.autoaccept.off.description": "Permissões de edição e escrita exigirão aprovação", + + "toast.model.none.title": "Nenhum modelo selecionado", + "toast.model.none.description": "Conecte um provedor para resumir esta sessão", + + "toast.file.loadFailed.title": "Falha ao carregar arquivo", + + "toast.session.share.copyFailed.title": "Falha ao copiar URL para a área de transferência", + "toast.session.share.success.title": "Sessão compartilhada", + "toast.session.share.success.description": "URL compartilhada copiada para a área de transferência!", + "toast.session.share.failed.title": "Falha ao compartilhar sessão", + "toast.session.share.failed.description": "Ocorreu um erro ao compartilhar a sessão", + + "toast.session.unshare.success.title": "Sessão não compartilhada", + "toast.session.unshare.success.description": "Sessão deixou de ser compartilhada com sucesso!", + "toast.session.unshare.failed.title": "Falha ao parar de compartilhar sessão", + "toast.session.unshare.failed.description": "Ocorreu um erro ao parar de compartilhar a sessão", + + "toast.session.listFailed.title": "Falha ao carregar sessões para {{project}}", + + "toast.update.title": "Atualização disponível", + "toast.update.description": "Uma nova versão do OpenCode ({{version}}) está disponível para instalação.", + "toast.update.action.installRestart": "Instalar e reiniciar", + "toast.update.action.notYet": "Agora não", + + "error.page.title": "Algo deu errado", + "error.page.description": "Ocorreu um erro ao carregar a aplicação.", + "error.page.details.label": "Detalhes do Erro", + "error.page.action.restart": "Reiniciar", + "error.page.action.checking": "Verificando...", + "error.page.action.checkUpdates": "Verificar atualizações", + "error.page.action.updateTo": "Atualizar para {{version}}", + "error.page.report.prefix": "Por favor, reporte este erro para a equipe do OpenCode", + "error.page.report.discord": "no Discord", + "error.page.version": "Versão: {{version}}", + + "error.dev.rootNotFound": + "Elemento raiz não encontrado. Você esqueceu de adicioná-lo ao seu index.html? Ou talvez o atributo id foi escrito incorretamente?", + + "error.globalSync.connectFailed": "Não foi possível conectar ao servidor. Há um servidor executando em `{{url}}`?", + + "error.chain.unknown": "Erro desconhecido", + "error.chain.causedBy": "Causado por:", + "error.chain.apiError": "Erro de API", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Pode tentar novamente: {{retryable}}", + "error.chain.responseBody": "Corpo da resposta:\n{{body}}", + "error.chain.didYouMean": "Você quis dizer: {{suggestions}}", + "error.chain.modelNotFound": "Modelo não encontrado: {{provider}}/{{model}}", + "error.chain.checkConfig": "Verifique os nomes de provedor/modelo na sua configuração (opencode.json)", + "error.chain.mcpFailed": 'Servidor MCP "{{name}}" falhou. Nota: OpenCode ainda não suporta autenticação MCP.', + "error.chain.providerAuthFailed": "Autenticação do provedor falhou ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Falha ao inicializar provedor "{{provider}}". Verifique credenciais e configuração.', + "error.chain.configJsonInvalid": "Arquivo de configuração em {{path}} não é um JSON(C) válido", + "error.chain.configJsonInvalidWithMessage": + "Arquivo de configuração em {{path}} não é um JSON(C) válido: {{message}}", + "error.chain.configDirectoryTypo": + 'Diretório "{{dir}}" em {{path}} não é válido. Renomeie o diretório para "{{suggestion}}" ou remova-o. Este é um erro de digitação comum.', + "error.chain.configFrontmatterError": "Falha ao analisar frontmatter em {{path}}:\n{{message}}", + "error.chain.configInvalid": "Arquivo de configuração em {{path}} é inválido", + "error.chain.configInvalidWithMessage": "Arquivo de configuração em {{path}} é inválido: {{message}}", + + "notification.permission.title": "Permissão necessária", + "notification.permission.description": "{{sessionTitle}} em {{projectName}} precisa de permissão", + "notification.question.title": "Pergunta", + "notification.question.description": "{{sessionTitle}} em {{projectName}} tem uma pergunta", + "notification.action.goToSession": "Ir para sessão", + + "notification.session.responseReady.title": "Resposta pronta", + "notification.session.error.title": "Erro na sessão", + "notification.session.error.fallbackDescription": "Ocorreu um erro", + + "home.recentProjects": "Projetos recentes", + "home.empty.title": "Nenhum projeto recente", + "home.empty.description": "Comece abrindo um projeto local", + + "session.tab.session": "Sessão", + "session.tab.review": "Revisão", + "session.tab.context": "Contexto", + "session.panel.reviewAndFiles": "Revisão e arquivos", + "session.review.filesChanged": "{{count}} Arquivos Alterados", + "session.review.loadingChanges": "Carregando alterações...", + "session.review.empty": "Nenhuma alteração nesta sessão ainda", + "session.messages.renderEarlier": "Renderizar mensagens anteriores", + "session.messages.loadingEarlier": "Carregando mensagens anteriores...", + "session.messages.loadEarlier": "Carregar mensagens anteriores", + "session.messages.loading": "Carregando mensagens...", + "session.messages.jumpToLatest": "Ir para a mais recente", + + "session.context.addToContext": "Adicionar {{selection}} ao contexto", + + "session.new.worktree.main": "Branch principal", + "session.new.worktree.mainWithBranch": "Branch principal ({{branch}})", + "session.new.worktree.create": "Criar novo worktree", + "session.new.lastModified": "Última modificação", + + "session.header.search.placeholder": "Buscar {{project}}", + "session.header.searchFiles": "Buscar arquivos", + + "session.share.popover.title": "Publicar na web", + "session.share.popover.description.shared": + "Esta sessão é pública na web. Está acessível para qualquer pessoa com o link.", + "session.share.popover.description.unshared": + "Compartilhar sessão publicamente na web. Estará acessível para qualquer pessoa com o link.", + "session.share.action.share": "Compartilhar", + "session.share.action.publish": "Publicar", + "session.share.action.publishing": "Publicando...", + "session.share.action.unpublish": "Cancelar publicação", + "session.share.action.unpublishing": "Cancelando publicação...", + "session.share.action.view": "Ver", + "session.share.copy.copied": "Copiado", + "session.share.copy.copyLink": "Copiar link", + + "lsp.tooltip.none": "Nenhum servidor LSP", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Carregando prompt...", + "terminal.loading": "Carregando terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Fechar terminal", + "terminal.connectionLost.title": "Conexão Perdida", + "terminal.connectionLost.description": + "A conexão do terminal foi interrompida. Isso pode acontecer quando o servidor reinicia.", + + "common.closeTab": "Fechar aba", + "common.dismiss": "Descartar", + "common.requestFailed": "Requisição falhou", + "common.moreOptions": "Mais opções", + "common.learnMore": "Saiba mais", + "common.rename": "Renomear", + "common.reset": "Redefinir", + "common.archive": "Arquivar", + "common.delete": "Excluir", + "common.close": "Fechar", + "common.edit": "Editar", + "common.loadMore": "Carregar mais", + "common.key.esc": "ESC", + + "sidebar.menu.toggle": "Alternar menu", + "sidebar.nav.projectsAndSessions": "Projetos e sessões", + "sidebar.settings": "Configurações", + "sidebar.help": "Ajuda", + "sidebar.workspaces.enable": "Habilitar espaços de trabalho", + "sidebar.workspaces.disable": "Desabilitar espaços de trabalho", + "sidebar.gettingStarted.title": "Começando", + "sidebar.gettingStarted.line1": "OpenCode inclui modelos gratuitos para você começar imediatamente.", + "sidebar.gettingStarted.line2": "Conecte qualquer provedor para usar modelos, incluindo Claude, GPT, Gemini etc.", + "sidebar.project.recentSessions": "Sessões recentes", + "sidebar.project.viewAllSessions": "Ver todas as sessões", + + "settings.section.desktop": "Desktop", + "settings.tab.general": "Geral", + "settings.tab.shortcuts": "Atalhos", + + "settings.general.section.appearance": "Aparência", + "settings.general.section.notifications": "Notificações do sistema", + "settings.general.section.sounds": "Efeitos sonoros", + + "settings.general.row.language.title": "Idioma", + "settings.general.row.language.description": "Alterar o idioma de exibição do OpenCode", + "settings.general.row.appearance.title": "Aparência", + "settings.general.row.appearance.description": "Personalize como o OpenCode aparece no seu dispositivo", + "settings.general.row.theme.title": "Tema", + "settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.", + "settings.general.row.font.title": "Fonte", + "settings.general.row.font.description": "Personalize a fonte monoespaçada usada em blocos de código", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "sound.option.alert01": "Alerta 01", + "sound.option.alert02": "Alerta 02", + "sound.option.alert03": "Alerta 03", + "sound.option.alert04": "Alerta 04", + "sound.option.alert05": "Alerta 05", + "sound.option.alert06": "Alerta 06", + "sound.option.alert07": "Alerta 07", + "sound.option.alert08": "Alerta 08", + "sound.option.alert09": "Alerta 09", + "sound.option.alert10": "Alerta 10", + "sound.option.bipbop01": "Bip-bop 01", + "sound.option.bipbop02": "Bip-bop 02", + "sound.option.bipbop03": "Bip-bop 03", + "sound.option.bipbop04": "Bip-bop 04", + "sound.option.bipbop05": "Bip-bop 05", + "sound.option.bipbop06": "Bip-bop 06", + "sound.option.bipbop07": "Bip-bop 07", + "sound.option.bipbop08": "Bip-bop 08", + "sound.option.bipbop09": "Bip-bop 09", + "sound.option.bipbop10": "Bip-bop 10", + "sound.option.staplebops01": "Staplebops 01", + "sound.option.staplebops02": "Staplebops 02", + "sound.option.staplebops03": "Staplebops 03", + "sound.option.staplebops04": "Staplebops 04", + "sound.option.staplebops05": "Staplebops 05", + "sound.option.staplebops06": "Staplebops 06", + "sound.option.staplebops07": "Staplebops 07", + "sound.option.nope01": "Não 01", + "sound.option.nope02": "Não 02", + "sound.option.nope03": "Não 03", + "sound.option.nope04": "Não 04", + "sound.option.nope05": "Não 05", + "sound.option.nope06": "Não 06", + "sound.option.nope07": "Não 07", + "sound.option.nope08": "Não 08", + "sound.option.nope09": "Não 09", + "sound.option.nope10": "Não 10", + "sound.option.nope11": "Não 11", + "sound.option.nope12": "Não 12", + "sound.option.yup01": "Sim 01", + "sound.option.yup02": "Sim 02", + "sound.option.yup03": "Sim 03", + "sound.option.yup04": "Sim 04", + "sound.option.yup05": "Sim 05", + "sound.option.yup06": "Sim 06", + + "settings.general.notifications.agent.title": "Agente", + "settings.general.notifications.agent.description": + "Mostrar notificação do sistema quando o agente estiver completo ou precisar de atenção", + "settings.general.notifications.permissions.title": "Permissões", + "settings.general.notifications.permissions.description": + "Mostrar notificação do sistema quando uma permissão for necessária", + "settings.general.notifications.errors.title": "Erros", + "settings.general.notifications.errors.description": "Mostrar notificação do sistema quando ocorrer um erro", + + "settings.general.sounds.agent.title": "Agente", + "settings.general.sounds.agent.description": "Reproduzir som quando o agente estiver completo ou precisar de atenção", + "settings.general.sounds.permissions.title": "Permissões", + "settings.general.sounds.permissions.description": "Reproduzir som quando uma permissão for necessária", + "settings.general.sounds.errors.title": "Erros", + "settings.general.sounds.errors.description": "Reproduzir som quando ocorrer um erro", + + "settings.shortcuts.title": "Atalhos de teclado", + "settings.shortcuts.reset.button": "Redefinir para padrões", + "settings.shortcuts.reset.toast.title": "Atalhos redefinidos", + "settings.shortcuts.reset.toast.description": "Atalhos de teclado foram redefinidos para os padrões.", + "settings.shortcuts.conflict.title": "Atalho já em uso", + "settings.shortcuts.conflict.description": "{{keybind}} já está atribuído a {{titles}}.", + "settings.shortcuts.unassigned": "Não atribuído", + "settings.shortcuts.pressKeys": "Pressione teclas", + "settings.shortcuts.search.placeholder": "Buscar atalhos", + "settings.shortcuts.search.empty": "Nenhum atalho encontrado", + + "settings.shortcuts.group.general": "Geral", + "settings.shortcuts.group.session": "Sessão", + "settings.shortcuts.group.navigation": "Navegação", + "settings.shortcuts.group.modelAndAgent": "Modelo e agente", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Provedores", + "settings.providers.description": "Configurações de provedores estarão disponíveis aqui.", + "settings.models.title": "Modelos", + "settings.models.description": "Configurações de modelos estarão disponíveis aqui.", + "settings.agents.title": "Agentes", + "settings.agents.description": "Configurações de agentes estarão disponíveis aqui.", + "settings.commands.title": "Comandos", + "settings.commands.description": "Configurações de comandos estarão disponíveis aqui.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "Configurações de MCP estarão disponíveis aqui.", + + "settings.permissions.title": "Permissões", + "settings.permissions.description": "Controle quais ferramentas o servidor pode usar por padrão.", + "settings.permissions.section.tools": "Ferramentas", + "settings.permissions.toast.updateFailed.title": "Falha ao atualizar permissões", + + "settings.permissions.action.allow": "Permitir", + "settings.permissions.action.ask": "Perguntar", + "settings.permissions.action.deny": "Negar", + + "settings.permissions.tool.read.title": "Ler", + "settings.permissions.tool.read.description": "Ler um arquivo (corresponde ao caminho do arquivo)", + "settings.permissions.tool.edit.title": "Editar", + "settings.permissions.tool.edit.description": + "Modificar arquivos, incluindo edições, escritas, patches e multi-edições", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Corresponder arquivos usando padrões glob", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Buscar conteúdo de arquivos usando expressões regulares", + "settings.permissions.tool.list.title": "Listar", + "settings.permissions.tool.list.description": "Listar arquivos dentro de um diretório", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Executar comandos shell", + "settings.permissions.tool.task.title": "Tarefa", + "settings.permissions.tool.task.description": "Lançar sub-agentes", + "settings.permissions.tool.skill.title": "Habilidade", + "settings.permissions.tool.skill.description": "Carregar uma habilidade por nome", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Executar consultas de servidor de linguagem", + "settings.permissions.tool.todoread.title": "Ler Tarefas", + "settings.permissions.tool.todoread.description": "Ler a lista de tarefas", + "settings.permissions.tool.todowrite.title": "Escrever Tarefas", + "settings.permissions.tool.todowrite.description": "Atualizar a lista de tarefas", + "settings.permissions.tool.webfetch.title": "Buscar Web", + "settings.permissions.tool.webfetch.description": "Buscar conteúdo de uma URL", + "settings.permissions.tool.websearch.title": "Pesquisa Web", + "settings.permissions.tool.websearch.description": "Pesquisar na web", + "settings.permissions.tool.codesearch.title": "Pesquisa de Código", + "settings.permissions.tool.codesearch.description": "Pesquisar código na web", + "settings.permissions.tool.external_directory.title": "Diretório Externo", + "settings.permissions.tool.external_directory.description": "Acessar arquivos fora do diretório do projeto", + "settings.permissions.tool.doom_loop.title": "Loop Infinito", + "settings.permissions.tool.doom_loop.description": "Detectar chamadas de ferramentas repetidas com entrada idêntica", + + "session.delete.failed.title": "Falha ao excluir sessão", + "session.delete.title": "Excluir sessão", + "session.delete.confirm": 'Excluir sessão "{{name}}"?', + "session.delete.button": "Excluir sessão", + + "workspace.new": "Novo espaço de trabalho", + "workspace.type.local": "local", + "workspace.type.sandbox": "sandbox", + "workspace.create.failed.title": "Falha ao criar espaço de trabalho", + "workspace.delete.failed.title": "Falha ao excluir espaço de trabalho", + "workspace.resetting.title": "Redefinindo espaço de trabalho", + "workspace.resetting.description": "Isso pode levar um minuto.", + "workspace.reset.failed.title": "Falha ao redefinir espaço de trabalho", + "workspace.reset.success.title": "Espaço de trabalho redefinido", + "workspace.reset.success.description": "Espaço de trabalho agora corresponde ao branch padrão.", + "workspace.status.checking": "Verificando alterações não mescladas...", + "workspace.status.error": "Não foi possível verificar o status do git.", + "workspace.status.clean": "Nenhuma alteração não mesclada detectada.", + "workspace.status.dirty": "Alterações não mescladas detectadas neste espaço de trabalho.", + "workspace.delete.title": "Excluir espaço de trabalho", + "workspace.delete.confirm": 'Excluir espaço de trabalho "{{name}}"?', + "workspace.delete.button": "Excluir espaço de trabalho", + "workspace.reset.title": "Redefinir espaço de trabalho", + "workspace.reset.confirm": 'Redefinir espaço de trabalho "{{name}}"?', + "workspace.reset.button": "Redefinir espaço de trabalho", + "workspace.reset.archived.none": "Nenhuma sessão ativa será arquivada.", + "workspace.reset.archived.one": "1 sessão será arquivada.", + "workspace.reset.archived.many": "{{count}} sessões serão arquivadas.", + "workspace.reset.note": "Isso redefinirá o espaço de trabalho para corresponder ao branch padrão.", +} diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts new file mode 100644 index 00000000000..b1e3f59c37c --- /dev/null +++ b/packages/app/src/i18n/da.ts @@ -0,0 +1,580 @@ +export const dict = { + "command.category.suggested": "Foreslået", + "command.category.view": "Vis", + "command.category.project": "Projekt", + "command.category.provider": "Udbyder", + "command.category.server": "Server", + "command.category.session": "Session", + "command.category.theme": "Tema", + "command.category.language": "Sprog", + "command.category.file": "Fil", + "command.category.terminal": "Terminal", + "command.category.model": "Model", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Tilladelser", + "command.category.workspace": "Arbejdsområde", + + "theme.scheme.system": "System", + "theme.scheme.light": "Lys", + "theme.scheme.dark": "Mørk", + + "command.sidebar.toggle": "Skift sidebjælke", + "command.project.open": "Åbn projekt", + "command.provider.connect": "Tilslut udbyder", + "command.server.switch": "Skift server", + "command.session.previous": "Forrige session", + "command.session.next": "Næste session", + "command.session.archive": "Arkivér session", + + "command.palette": "Kommandopalette", + + "command.theme.cycle": "Skift tema", + "command.theme.set": "Brug tema: {{theme}}", + "command.theme.scheme.cycle": "Skift farveskema", + "command.theme.scheme.set": "Brug farveskema: {{scheme}}", + + "command.language.cycle": "Skift sprog", + "command.language.set": "Brug sprog: {{language}}", + + "command.session.new": "Ny session", + "command.file.open": "Åbn fil", + "command.file.open.description": "Søg i filer og kommandoer", + "command.terminal.toggle": "Skift terminal", + "command.review.toggle": "Skift gennemgang", + "command.terminal.new": "Ny terminal", + "command.terminal.new.description": "Opret en ny terminalfane", + "command.steps.toggle": "Skift trin", + "command.steps.toggle.description": "Vis eller skjul trin for den aktuelle besked", + "command.message.previous": "Forrige besked", + "command.message.previous.description": "Gå til den forrige brugerbesked", + "command.message.next": "Næste besked", + "command.message.next.description": "Gå til den næste brugerbesked", + "command.model.choose": "Vælg model", + "command.model.choose.description": "Vælg en anden model", + "command.mcp.toggle": "Skift MCP'er", + "command.mcp.toggle.description": "Skift MCP'er", + "command.agent.cycle": "Skift agent", + "command.agent.cycle.description": "Skift til næste agent", + "command.agent.cycle.reverse": "Skift agent baglæns", + "command.agent.cycle.reverse.description": "Skift til forrige agent", + "command.model.variant.cycle": "Skift tænkeindsats", + "command.model.variant.cycle.description": "Skift til næste indsatsniveau", + "command.permissions.autoaccept.enable": "Accepter ændringer automatisk", + "command.permissions.autoaccept.disable": "Stop automatisk accept af ændringer", + "command.session.undo": "Fortryd", + "command.session.undo.description": "Fortryd den sidste besked", + "command.session.redo": "Omgør", + "command.session.redo.description": "Omgør den sidste fortrudte besked", + "command.session.compact": "Komprimér session", + "command.session.compact.description": "Opsummer sessionen for at reducere kontekststørrelsen", + "command.session.fork": "Forgren fra besked", + "command.session.fork.description": "Opret en ny session fra en tidligere besked", + "command.session.share": "Del session", + "command.session.share.description": "Del denne session og kopier URL'en til udklipsholderen", + "command.session.unshare": "Stop deling af session", + "command.session.unshare.description": "Stop med at dele denne session", + + "palette.search.placeholder": "Søg i filer og kommandoer", + "palette.empty": "Ingen resultater fundet", + "palette.group.commands": "Kommandoer", + "palette.group.files": "Filer", + + "dialog.provider.search.placeholder": "Søg udbydere", + "dialog.provider.empty": "Ingen udbydere fundet", + "dialog.provider.group.popular": "Populære", + "dialog.provider.group.other": "Andre", + "dialog.provider.tag.recommended": "Anbefalet", + "dialog.provider.anthropic.note": "Forbind med Claude Pro/Max eller API-nøgle", + + "dialog.model.select.title": "Vælg model", + "dialog.model.search.placeholder": "Søg modeller", + "dialog.model.empty": "Ingen modeller fundet", + "dialog.model.manage": "Administrer modeller", + "dialog.model.manage.description": "Tilpas hvilke modeller der vises i modelvælgeren.", + + "dialog.model.unpaid.freeModels.title": "Gratis modeller leveret af OpenCode", + "dialog.model.unpaid.addMore.title": "Tilføj flere modeller fra populære udbydere", + + "dialog.provider.viewAll": "Vis alle udbydere", + + "provider.connect.title": "Forbind {{provider}}", + "provider.connect.title.anthropicProMax": "Log ind med Claude Pro/Max", + "provider.connect.selectMethod": "Vælg loginmetode for {{provider}}.", + "provider.connect.method.apiKey": "API-nøgle", + "provider.connect.status.inProgress": "Godkendelse i gang...", + "provider.connect.status.waiting": "Venter på godkendelse...", + "provider.connect.status.failed": "Godkendelse mislykkedes: {{error}}", + "provider.connect.apiKey.description": + "Indtast din {{provider}} API-nøgle for at forbinde din konto og bruge {{provider}} modeller i OpenCode.", + "provider.connect.apiKey.label": "{{provider}} API-nøgle", + "provider.connect.apiKey.placeholder": "API-nøgle", + "provider.connect.apiKey.required": "API-nøgle er påkrævet", + "provider.connect.opencodeZen.line1": + "OpenCode Zen giver dig adgang til et udvalg af pålidelige optimerede modeller til kodningsagenter.", + "provider.connect.opencodeZen.line2": + "Med en enkelt API-nøgle får du adgang til modeller som Claude, GPT, Gemini, GLM og flere.", + "provider.connect.opencodeZen.visit.prefix": "Besøg ", + "provider.connect.opencodeZen.visit.suffix": " for at hente din API-nøgle.", + "provider.connect.oauth.code.visit.prefix": "Besøg ", + "provider.connect.oauth.code.visit.link": "dette link", + "provider.connect.oauth.code.visit.suffix": + " for at hente din godkendelseskode for at forbinde din konto og bruge {{provider}} modeller i OpenCode.", + "provider.connect.oauth.code.label": "{{method}} godkendelseskode", + "provider.connect.oauth.code.placeholder": "Godkendelseskode", + "provider.connect.oauth.code.required": "Godkendelseskode er påkrævet", + "provider.connect.oauth.code.invalid": "Ugyldig godkendelseskode", + "provider.connect.oauth.auto.visit.prefix": "Besøg ", + "provider.connect.oauth.auto.visit.link": "dette link", + "provider.connect.oauth.auto.visit.suffix": + " og indtast koden nedenfor for at forbinde din konto og bruge {{provider}} modeller i OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Bekræftelseskode", + "provider.connect.toast.connected.title": "{{provider}} forbundet", + "provider.connect.toast.connected.description": "{{provider}} modeller er nu tilgængelige.", + + "model.tag.free": "Gratis", + "model.tag.latest": "Nyeste", + + "common.search.placeholder": "Søg", + "common.goBack": "Gå tilbage", + "common.loading": "Indlæser", + "common.cancel": "Annuller", + "common.submit": "Indsend", + "common.save": "Gem", + "common.saving": "Gemmer...", + "common.default": "Standard", + "common.attachment": "vedhæftning", + + "prompt.placeholder.shell": "Indtast shell-kommando...", + "prompt.placeholder.normal": 'Spørg om hvad som helst... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc for at afslutte", + + "prompt.example.1": "Ret en TODO i koden", + "prompt.example.2": "Hvad er teknologistakken for dette projekt?", + "prompt.example.3": "Ret ødelagte tests", + "prompt.example.4": "Forklar hvordan godkendelse fungerer", + "prompt.example.5": "Find og ret sikkerhedshuller", + "prompt.example.6": "Tilføj enhedstests for brugerservice", + "prompt.example.7": "Refaktorer denne funktion så den er mere læsbar", + "prompt.example.8": "Hvad betyder denne fejl?", + "prompt.example.9": "Hjælp mig med at debugge dette problem", + "prompt.example.10": "Generer API-dokumentation", + "prompt.example.11": "Optimer databaseforespørgsler", + "prompt.example.12": "Tilføj validering af input", + "prompt.example.13": "Opret en ny komponent til...", + "prompt.example.14": "Hvordan deployerer jeg dette projekt?", + "prompt.example.15": "Gennemgå min kode for bedste praksis", + "prompt.example.16": "Tilføj fejlhåndtering til denne funktion", + "prompt.example.17": "Forklar dette regex-mønster", + "prompt.example.18": "Konverter dette til TypeScript", + "prompt.example.19": "Tilføj logning i hele koden", + "prompt.example.20": "Hvilke afhængigheder er forældede?", + "prompt.example.21": "Hjælp mig med at skrive et migreringsscript", + "prompt.example.22": "Implementer caching for dette endpoint", + "prompt.example.23": "Tilføj sideinddeling til denne liste", + "prompt.example.24": "Opret en CLI-kommando til...", + "prompt.example.25": "Hvordan fungerer miljøvariabler her?", + + "prompt.popover.emptyResults": "Ingen matchende resultater", + "prompt.popover.emptyCommands": "Ingen matchende kommandoer", + "prompt.dropzone.label": "Slip billeder eller PDF'er her", + "prompt.slash.badge.custom": "brugerdefineret", + "prompt.context.active": "aktiv", + "prompt.context.includeActiveFile": "Inkluder aktiv fil", + "prompt.context.removeActiveFile": "Fjern aktiv fil fra kontekst", + "prompt.context.removeFile": "Fjern fil fra kontekst", + "prompt.action.attachFile": "Vedhæft fil", + "prompt.attachment.remove": "Fjern vedhæftning", + "prompt.action.send": "Send", + "prompt.action.stop": "Stop", + + "prompt.toast.pasteUnsupported.title": "Ikke understøttet indsæt", + "prompt.toast.pasteUnsupported.description": "Kun billeder eller PDF'er kan indsættes her.", + "prompt.toast.modelAgentRequired.title": "Vælg en agent og model", + "prompt.toast.modelAgentRequired.description": "Vælg en agent og model før du sender en forespørgsel.", + "prompt.toast.worktreeCreateFailed.title": "Kunne ikke oprette worktree", + "prompt.toast.sessionCreateFailed.title": "Kunne ikke oprette session", + "prompt.toast.shellSendFailed.title": "Kunne ikke sende shell-kommando", + "prompt.toast.commandSendFailed.title": "Kunne ikke sende kommando", + "prompt.toast.promptSendFailed.title": "Kunne ikke sende forespørgsel", + + "dialog.mcp.title": "MCP'er", + "dialog.mcp.description": "{{enabled}} af {{total}} aktiveret", + "dialog.mcp.empty": "Ingen MCP'er konfigureret", + + "mcp.status.connected": "forbundet", + "mcp.status.failed": "mislykkedes", + "mcp.status.needs_auth": "kræver godkendelse", + "mcp.status.disabled": "deaktiveret", + + "dialog.fork.empty": "Ingen beskeder at forgrene fra", + + "dialog.directory.search.placeholder": "Søg mapper", + "dialog.directory.empty": "Ingen mapper fundet", + + "dialog.server.title": "Servere", + "dialog.server.description": "Skift hvilken OpenCode-server denne app forbinder til.", + "dialog.server.search.placeholder": "Søg servere", + "dialog.server.empty": "Ingen servere endnu", + "dialog.server.add.title": "Tilføj en server", + "dialog.server.add.url": "Server URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Kunne ikke forbinde til server", + "dialog.server.add.checking": "Tjekker...", + "dialog.server.add.button": "Tilføj", + "dialog.server.default.title": "Standardserver", + "dialog.server.default.description": + "Forbind til denne server ved start af app i stedet for at starte en lokal server. Kræver genstart.", + "dialog.server.default.none": "Ingen server valgt", + "dialog.server.default.set": "Sæt nuværende server som standard", + "dialog.server.default.clear": "Ryd", + "dialog.server.action.remove": "Fjern server", + + "dialog.project.edit.title": "Rediger projekt", + "dialog.project.edit.name": "Navn", + "dialog.project.edit.icon": "Ikon", + "dialog.project.edit.icon.alt": "Projektikon", + "dialog.project.edit.icon.hint": "Klik eller træk et billede", + "dialog.project.edit.icon.recommended": "Anbefalet: 128x128px", + "dialog.project.edit.color": "Farve", + "dialog.project.edit.color.select": "Vælg farven {{color}}", + + "context.breakdown.title": "Kontekstfordeling", + "context.breakdown.note": + 'Omtrentlig fordeling af input-tokens. "Andre" inkluderer værktøjsdefinitioner og overhead.', + "context.breakdown.system": "System", + "context.breakdown.user": "Bruger", + "context.breakdown.assistant": "Assistent", + "context.breakdown.tool": "Værktøjskald", + "context.breakdown.other": "Andre", + + "context.systemPrompt.title": "Systemprompt", + "context.rawMessages.title": "Rå beskeder", + + "context.stats.session": "Session", + "context.stats.messages": "Beskeder", + "context.stats.provider": "Udbyder", + "context.stats.model": "Model", + "context.stats.limit": "Kontekstgrænse", + "context.stats.totalTokens": "Total Tokens", + "context.stats.usage": "Forbrug", + "context.stats.inputTokens": "Input Tokens", + "context.stats.outputTokens": "Output Tokens", + "context.stats.reasoningTokens": "Tænke Tokens", + "context.stats.cacheTokens": "Cache Tokens (læs/skriv)", + "context.stats.userMessages": "Brugerbeskeder", + "context.stats.assistantMessages": "Assistentbeskeder", + "context.stats.totalCost": "Samlede omkostninger", + "context.stats.sessionCreated": "Session oprettet", + "context.stats.lastActivity": "Seneste aktivitet", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Forbrug", + "context.usage.cost": "Omkostning", + "context.usage.clickToView": "Klik for at se kontekst", + "context.usage.view": "Se kontekstforbrug", + + "language.en": "Engelsk", + "language.zh": "Kinesisk (forenklet)", + "language.zht": "Kinesisk (traditionelt)", + "language.ko": "Koreansk", + "language.de": "Tysk", + "language.es": "Spansk", + "language.fr": "Fransk", + "language.ja": "Japansk", + "language.da": "Dansk", + "language.ru": "Russisk", + "language.pl": "Polsk", + "language.ar": "Arabisk", + "language.no": "Norsk", + "language.br": "Portugisisk (Brasilien)", + + "toast.language.title": "Sprog", + "toast.language.description": "Skiftede til {{language}}", + + "toast.theme.title": "Tema skiftet", + "toast.scheme.title": "Farveskema", + + "toast.permissions.autoaccept.on.title": "Accepterer ændringer automatisk", + "toast.permissions.autoaccept.on.description": "Redigerings- og skrivetilladelser vil automatisk blive godkendt", + "toast.permissions.autoaccept.off.title": "Stoppede automatisk accept af ændringer", + "toast.permissions.autoaccept.off.description": "Redigerings- og skrivetilladelser vil kræve godkendelse", + + "toast.model.none.title": "Ingen model valgt", + "toast.model.none.description": "Forbind en udbyder for at opsummere denne session", + + "toast.file.loadFailed.title": "Kunne ikke indlæse fil", + + "toast.session.share.copyFailed.title": "Kunne ikke kopiere URL til udklipsholder", + "toast.session.share.success.title": "Session delt", + "toast.session.share.success.description": "Delings-URL kopieret til udklipsholder!", + "toast.session.share.failed.title": "Kunne ikke dele session", + "toast.session.share.failed.description": "Der opstod en fejl under deling af sessionen", + + "toast.session.unshare.success.title": "Deling af session stoppet", + "toast.session.unshare.success.description": "Deling af session blev stoppet!", + "toast.session.unshare.failed.title": "Kunne ikke stoppe deling af session", + "toast.session.unshare.failed.description": "Der opstod en fejl under stop af sessionsdeling", + + "toast.session.listFailed.title": "Kunne ikke indlæse sessioner for {{project}}", + + "toast.update.title": "Opdatering tilgængelig", + "toast.update.description": "En ny version af OpenCode ({{version}}) er nu tilgængelig til installation.", + "toast.update.action.installRestart": "Installer og genstart", + "toast.update.action.notYet": "Ikke endnu", + + "error.page.title": "Noget gik galt", + "error.page.description": "Der opstod en fejl under indlæsning af applikationen.", + "error.page.details.label": "Fejldetaljer", + "error.page.action.restart": "Genstart", + "error.page.action.checking": "Tjekker...", + "error.page.action.checkUpdates": "Tjek for opdateringer", + "error.page.action.updateTo": "Opdater til {{version}}", + "error.page.report.prefix": "Rapporter venligst denne fejl til OpenCode-teamet", + "error.page.report.discord": "på Discord", + "error.page.version": "Version: {{version}}", + + "error.dev.rootNotFound": + "Rodelement ikke fundet. Har du glemt at tilføje det til din index.html? Eller måske er id-attributten stavet forkert?", + + "error.globalSync.connectFailed": "Kunne ikke forbinde til server. Kører der en server på `{{url}}`?", + + "error.chain.unknown": "Ukendt fejl", + "error.chain.causedBy": "Forårsaget af:", + "error.chain.apiError": "API-fejl", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Kan forsøges igen: {{retryable}}", + "error.chain.responseBody": "Svarindhold:\n{{body}}", + "error.chain.didYouMean": "Mente du: {{suggestions}}", + "error.chain.modelNotFound": "Model ikke fundet: {{provider}}/{{model}}", + "error.chain.checkConfig": "Tjek dine konfigurations (opencode.json) udbyder/modelnavne", + "error.chain.mcpFailed": 'MCP-server "{{name}}" fejlede. Bemærk, OpenCode understøtter ikke MCP-godkendelse endnu.', + "error.chain.providerAuthFailed": "Udbydergodkendelse mislykkedes ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Kunne ikke initialisere udbyder "{{provider}}". Tjek legitimationsoplysninger og konfiguration.', + "error.chain.configJsonInvalid": "Konfigurationsfil på {{path}} er ikke gyldig JSON(C)", + "error.chain.configJsonInvalidWithMessage": "Konfigurationsfil på {{path}} er ikke gyldig JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Mappe "{{dir}}" i {{path}} er ikke gyldig. Omdøb mappen til "{{suggestion}}" eller fjern den. Dette er en almindelig slåfejl.', + "error.chain.configFrontmatterError": "Kunne ikke parse frontmatter i {{path}}:\n{{message}}", + "error.chain.configInvalid": "Konfigurationsfil på {{path}} er ugyldig", + "error.chain.configInvalidWithMessage": "Konfigurationsfil på {{path}} er ugyldig: {{message}}", + + "notification.permission.title": "Tilladelse påkrævet", + "notification.permission.description": "{{sessionTitle}} i {{projectName}} kræver tilladelse", + "notification.question.title": "Spørgsmål", + "notification.question.description": "{{sessionTitle}} i {{projectName}} har et spørgsmål", + "notification.action.goToSession": "Gå til session", + + "notification.session.responseReady.title": "Svar klar", + "notification.session.error.title": "Sessionsfejl", + "notification.session.error.fallbackDescription": "Der opstod en fejl", + + "home.recentProjects": "Seneste projekter", + "home.empty.title": "Ingen seneste projekter", + "home.empty.description": "Kom i gang ved at åbne et lokalt projekt", + + "session.tab.session": "Session", + "session.tab.review": "Gennemgang", + "session.tab.context": "Kontekst", + "session.panel.reviewAndFiles": "Gennemgang og filer", + "session.review.filesChanged": "{{count}} Filer ændret", + "session.review.loadingChanges": "Indlæser ændringer...", + "session.review.empty": "Ingen ændringer i denne session endnu", + "session.messages.renderEarlier": "Vis tidligere beskeder", + "session.messages.loadingEarlier": "Indlæser tidligere beskeder...", + "session.messages.loadEarlier": "Indlæs tidligere beskeder", + "session.messages.loading": "Indlæser beskeder...", + + "session.context.addToContext": "Tilføj {{selection}} til kontekst", + + "session.new.worktree.main": "Hovedgren", + "session.new.worktree.mainWithBranch": "Hovedgren ({{branch}})", + "session.new.worktree.create": "Opret nyt worktree", + "session.new.lastModified": "Sidst ændret", + + "session.header.search.placeholder": "Søg {{project}}", + "session.header.searchFiles": "Søg efter filer", + + "session.share.popover.title": "Udgiv på nettet", + "session.share.popover.description.shared": + "Denne session er offentlig på nettet. Den er tilgængelig for alle med linket.", + "session.share.popover.description.unshared": + "Del session offentligt på nettet. Den vil være tilgængelig for alle med linket.", + "session.share.action.share": "Del", + "session.share.action.publish": "Udgiv", + "session.share.action.publishing": "Udgiver...", + "session.share.action.unpublish": "Afpublicer", + "session.share.action.unpublishing": "Afpublicerer...", + "session.share.action.view": "Vis", + "session.share.copy.copied": "Kopieret", + "session.share.copy.copyLink": "Kopier link", + + "lsp.tooltip.none": "Ingen LSP-servere", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Indlæser prompt...", + "terminal.loading": "Indlæser terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Luk terminal", + + "common.closeTab": "Luk fane", + "common.dismiss": "Afvis", + "common.requestFailed": "Forespørgsel mislykkedes", + "common.moreOptions": "Flere muligheder", + "common.learnMore": "Lær mere", + "common.rename": "Omdøb", + "common.reset": "Nulstil", + "common.archive": "Arkivér", + "common.delete": "Slet", + "common.close": "Luk", + "common.edit": "Rediger", + "common.loadMore": "Indlæs flere", + + "sidebar.nav.projectsAndSessions": "Projekter og sessioner", + "sidebar.settings": "Indstillinger", + "sidebar.help": "Hjælp", + "sidebar.workspaces.enable": "Aktiver arbejdsområder", + "sidebar.workspaces.disable": "Deaktiver arbejdsområder", + "sidebar.gettingStarted.title": "Kom i gang", + "sidebar.gettingStarted.line1": "OpenCode inkluderer gratis modeller så du kan starte med det samme.", + "sidebar.gettingStarted.line2": "Forbind enhver udbyder for at bruge modeller, inkl. Claude, GPT, Gemini osv.", + "sidebar.project.recentSessions": "Seneste sessioner", + "sidebar.project.viewAllSessions": "Vis alle sessioner", + + "settings.section.desktop": "Desktop", + "settings.tab.general": "Generelt", + "settings.tab.shortcuts": "Genveje", + + "settings.general.section.appearance": "Udseende", + "settings.general.section.notifications": "Systemmeddelelser", + "settings.general.section.sounds": "Lydeffekter", + + "settings.general.row.language.title": "Sprog", + "settings.general.row.language.description": "Ændr visningssproget for OpenCode", + "settings.general.row.appearance.title": "Udseende", + "settings.general.row.appearance.description": "Tilpas hvordan OpenCode ser ud på din enhed", + "settings.general.row.theme.title": "Tema", + "settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.", + "settings.general.row.font.title": "Skrifttype", + "settings.general.row.font.description": "Tilpas mono-skrifttypen brugt i kodeblokke", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Vis systemmeddelelse når agenten er færdig eller kræver opmærksomhed", + "settings.general.notifications.permissions.title": "Tilladelser", + "settings.general.notifications.permissions.description": "Vis systemmeddelelse når en tilladelse er påkrævet", + "settings.general.notifications.errors.title": "Fejl", + "settings.general.notifications.errors.description": "Vis systemmeddelelse når der opstår en fejl", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Afspil lyd når agenten er færdig eller kræver opmærksomhed", + "settings.general.sounds.permissions.title": "Tilladelser", + "settings.general.sounds.permissions.description": "Afspil lyd når en tilladelse er påkrævet", + "settings.general.sounds.errors.title": "Fejl", + "settings.general.sounds.errors.description": "Afspil lyd når der opstår en fejl", + + "settings.shortcuts.title": "Tastaturgenveje", + "settings.shortcuts.reset.button": "Nulstil til standard", + "settings.shortcuts.reset.toast.title": "Genveje nulstillet", + "settings.shortcuts.reset.toast.description": "Tastaturgenveje er blevet nulstillet til standard.", + "settings.shortcuts.conflict.title": "Genvej allerede i brug", + "settings.shortcuts.conflict.description": "{{keybind}} er allerede tildelt til {{titles}}.", + "settings.shortcuts.unassigned": "Ikke tildelt", + "settings.shortcuts.pressKeys": "Tryk på taster", + "settings.shortcuts.search.placeholder": "Søg genveje", + "settings.shortcuts.search.empty": "Ingen genveje fundet", + + "settings.shortcuts.group.general": "Generelt", + "settings.shortcuts.group.session": "Session", + "settings.shortcuts.group.navigation": "Navigation", + "settings.shortcuts.group.modelAndAgent": "Model og agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Udbydere", + "settings.providers.description": "Udbyderindstillinger vil kunne konfigureres her.", + "settings.models.title": "Modeller", + "settings.models.description": "Modelindstillinger vil kunne konfigureres her.", + "settings.agents.title": "Agenter", + "settings.agents.description": "Agentindstillinger vil kunne konfigureres her.", + "settings.commands.title": "Kommandoer", + "settings.commands.description": "Kommandoindstillinger vil kunne konfigureres her.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP-indstillinger vil kunne konfigureres her.", + + "settings.permissions.title": "Tilladelser", + "settings.permissions.description": "Styr hvilke værktøjer serveren kan bruge som standard.", + "settings.permissions.section.tools": "Værktøjer", + "settings.permissions.toast.updateFailed.title": "Kunne ikke opdatere tilladelser", + + "settings.permissions.action.allow": "Tillad", + "settings.permissions.action.ask": "Spørg", + "settings.permissions.action.deny": "Afvis", + + "settings.permissions.tool.read.title": "Læs", + "settings.permissions.tool.read.description": "Læsning af en fil (matcher filstien)", + "settings.permissions.tool.edit.title": "Rediger", + "settings.permissions.tool.edit.description": + "Ændre filer, herunder redigeringer, skrivninger, patches og multi-redigeringer", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Match filer ved hjælp af glob-mønstre", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Søg i filindhold ved hjælp af regulære udtryk", + "settings.permissions.tool.list.title": "Liste", + "settings.permissions.tool.list.description": "List filer i en mappe", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Kør shell-kommandoer", + "settings.permissions.tool.task.title": "Opgave", + "settings.permissions.tool.task.description": "Start underagenter", + "settings.permissions.tool.skill.title": "Færdighed", + "settings.permissions.tool.skill.description": "Indlæs en færdighed efter navn", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Kør sprogserverforespørgsler", + "settings.permissions.tool.todoread.title": "Læs To-do", + "settings.permissions.tool.todoread.description": "Læs to-do listen", + "settings.permissions.tool.todowrite.title": "Skriv To-do", + "settings.permissions.tool.todowrite.description": "Opdater to-do listen", + "settings.permissions.tool.webfetch.title": "Webhentning", + "settings.permissions.tool.webfetch.description": "Hent indhold fra en URL", + "settings.permissions.tool.websearch.title": "Websøgning", + "settings.permissions.tool.websearch.description": "Søg på nettet", + "settings.permissions.tool.codesearch.title": "Kodesøgning", + "settings.permissions.tool.codesearch.description": "Søg kode på nettet", + "settings.permissions.tool.external_directory.title": "Ekstern mappe", + "settings.permissions.tool.external_directory.description": "Få adgang til filer uden for projektmappen", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "Opdag gentagne værktøjskald med identisk input", + + "session.delete.failed.title": "Kunne ikke slette session", + "session.delete.title": "Slet session", + "session.delete.confirm": 'Slet session "{{name}}"?', + "session.delete.button": "Slet session", + + "workspace.new": "Nyt arbejdsområde", + "workspace.type.local": "lokal", + "workspace.type.sandbox": "sandkasse", + "workspace.create.failed.title": "Kunne ikke oprette arbejdsområde", + "workspace.delete.failed.title": "Kunne ikke slette arbejdsområde", + "workspace.resetting.title": "Nulstiller arbejdsområde", + "workspace.resetting.description": "Dette kan tage et minut.", + "workspace.reset.failed.title": "Kunne ikke nulstille arbejdsområde", + "workspace.reset.success.title": "Arbejdsområde nulstillet", + "workspace.reset.success.description": "Arbejdsområdet matcher nu hovedgrenen.", + "workspace.status.checking": "Tjekker for uflettede ændringer...", + "workspace.status.error": "Kunne ikke bekræfte git-status.", + "workspace.status.clean": "Ingen uflettede ændringer fundet.", + "workspace.status.dirty": "Uflettede ændringer fundet i dette arbejdsområde.", + "workspace.delete.title": "Slet arbejdsområde", + "workspace.delete.confirm": 'Slet arbejdsområde "{{name}}"?', + "workspace.delete.button": "Slet arbejdsområde", + "workspace.reset.title": "Nulstil arbejdsområde", + "workspace.reset.confirm": 'Nulstil arbejdsområde "{{name}}"?', + "workspace.reset.button": "Nulstil arbejdsområde", + "workspace.reset.archived.none": "Ingen aktive sessioner vil blive arkiveret.", + "workspace.reset.archived.one": "1 session vil blive arkiveret.", + "workspace.reset.archived.many": "{{count}} sessioner vil blive arkiveret.", + "workspace.reset.note": "Dette vil nulstille arbejdsområdet til at matche hovedgrenen.", +} diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts new file mode 100644 index 00000000000..9b7d1e5e6af --- /dev/null +++ b/packages/app/src/i18n/de.ts @@ -0,0 +1,589 @@ +import { dict as en } from "./en" + +type Keys = keyof typeof en + +export const dict = { + "command.category.suggested": "Vorgeschlagen", + "command.category.view": "Ansicht", + "command.category.project": "Projekt", + "command.category.provider": "Anbieter", + "command.category.server": "Server", + "command.category.session": "Sitzung", + "command.category.theme": "Thema", + "command.category.language": "Sprache", + "command.category.file": "Datei", + "command.category.terminal": "Terminal", + "command.category.model": "Modell", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Berechtigungen", + "command.category.workspace": "Arbeitsbereich", + + "theme.scheme.system": "System", + "theme.scheme.light": "Hell", + "theme.scheme.dark": "Dunkel", + + "command.sidebar.toggle": "Seitenleiste umschalten", + "command.project.open": "Projekt öffnen", + "command.provider.connect": "Anbieter verbinden", + "command.server.switch": "Server wechseln", + "command.session.previous": "Vorherige Sitzung", + "command.session.next": "Nächste Sitzung", + "command.session.archive": "Sitzung archivieren", + + "command.palette": "Befehlspalette", + + "command.theme.cycle": "Thema wechseln", + "command.theme.set": "Thema verwenden: {{theme}}", + "command.theme.scheme.cycle": "Farbschema wechseln", + "command.theme.scheme.set": "Farbschema verwenden: {{scheme}}", + + "command.language.cycle": "Sprache wechseln", + "command.language.set": "Sprache verwenden: {{language}}", + + "command.session.new": "Neue Sitzung", + "command.file.open": "Datei öffnen", + "command.file.open.description": "Dateien und Befehle durchsuchen", + "command.terminal.toggle": "Terminal umschalten", + "command.review.toggle": "Überprüfung umschalten", + "command.terminal.new": "Neues Terminal", + "command.terminal.new.description": "Neuen Terminal-Tab erstellen", + "command.steps.toggle": "Schritte umschalten", + "command.steps.toggle.description": "Schritte für die aktuelle Nachricht anzeigen oder ausblenden", + "command.message.previous": "Vorherige Nachricht", + "command.message.previous.description": "Zur vorherigen Benutzernachricht gehen", + "command.message.next": "Nächste Nachricht", + "command.message.next.description": "Zur nächsten Benutzernachricht gehen", + "command.model.choose": "Modell wählen", + "command.model.choose.description": "Ein anderes Modell auswählen", + "command.mcp.toggle": "MCPs umschalten", + "command.mcp.toggle.description": "MCPs umschalten", + "command.agent.cycle": "Agent wechseln", + "command.agent.cycle.description": "Zum nächsten Agenten wechseln", + "command.agent.cycle.reverse": "Agent rückwärts wechseln", + "command.agent.cycle.reverse.description": "Zum vorherigen Agenten wechseln", + "command.model.variant.cycle": "Denkaufwand wechseln", + "command.model.variant.cycle.description": "Zum nächsten Aufwandslevel wechseln", + "command.permissions.autoaccept.enable": "Änderungen automatisch akzeptieren", + "command.permissions.autoaccept.disable": "Automatische Annahme von Änderungen stoppen", + "command.session.undo": "Rückgängig", + "command.session.undo.description": "Letzte Nachricht rückgängig machen", + "command.session.redo": "Wiederherstellen", + "command.session.redo.description": "Letzte rückgängig gemachte Nachricht wiederherstellen", + "command.session.compact": "Sitzung komprimieren", + "command.session.compact.description": "Sitzung zusammenfassen, um die Kontextgröße zu reduzieren", + "command.session.fork": "Von Nachricht abzweigen", + "command.session.fork.description": "Neue Sitzung aus einer früheren Nachricht erstellen", + "command.session.share": "Sitzung teilen", + "command.session.share.description": "Diese Sitzung teilen und URL in die Zwischenablage kopieren", + "command.session.unshare": "Teilen der Sitzung aufheben", + "command.session.unshare.description": "Teilen dieser Sitzung beenden", + + "palette.search.placeholder": "Dateien und Befehle durchsuchen", + "palette.empty": "Keine Ergebnisse gefunden", + "palette.group.commands": "Befehle", + "palette.group.files": "Dateien", + + "dialog.provider.search.placeholder": "Anbieter durchsuchen", + "dialog.provider.empty": "Keine Anbieter gefunden", + "dialog.provider.group.popular": "Beliebt", + "dialog.provider.group.other": "Andere", + "dialog.provider.tag.recommended": "Empfohlen", + "dialog.provider.anthropic.note": "Mit Claude Pro/Max oder API-Schlüssel verbinden", + + "dialog.model.select.title": "Modell auswählen", + "dialog.model.search.placeholder": "Modelle durchsuchen", + "dialog.model.empty": "Keine Modellergebnisse", + "dialog.model.manage": "Modelle verwalten", + "dialog.model.manage.description": "Anpassen, welche Modelle in der Modellauswahl erscheinen.", + + "dialog.model.unpaid.freeModels.title": "Kostenlose Modelle von OpenCode", + "dialog.model.unpaid.addMore.title": "Weitere Modelle von beliebten Anbietern hinzufügen", + + "dialog.provider.viewAll": "Alle Anbieter anzeigen", + + "provider.connect.title": "{{provider}} verbinden", + "provider.connect.title.anthropicProMax": "Mit Claude Pro/Max anmelden", + "provider.connect.selectMethod": "Anmeldemethode für {{provider}} auswählen.", + "provider.connect.method.apiKey": "API-Schlüssel", + "provider.connect.status.inProgress": "Autorisierung läuft...", + "provider.connect.status.waiting": "Warten auf Autorisierung...", + "provider.connect.status.failed": "Autorisierung fehlgeschlagen: {{error}}", + "provider.connect.apiKey.description": + "Geben Sie Ihren {{provider}} API-Schlüssel ein, um Ihr Konto zu verbinden und {{provider}} Modelle in OpenCode zu nutzen.", + "provider.connect.apiKey.label": "{{provider}} API-Schlüssel", + "provider.connect.apiKey.placeholder": "API-Schlüssel", + "provider.connect.apiKey.required": "API-Schlüssel ist erforderlich", + "provider.connect.opencodeZen.line1": + "OpenCode Zen bietet Ihnen Zugriff auf eine kuratierte Auswahl zuverlässiger, optimierter Modelle für Coding-Agenten.", + "provider.connect.opencodeZen.line2": + "Mit einem einzigen API-Schlüssel erhalten Sie Zugriff auf Modelle wie Claude, GPT, Gemini, GLM und mehr.", + "provider.connect.opencodeZen.visit.prefix": "Besuchen Sie ", + "provider.connect.opencodeZen.visit.suffix": ", um Ihren API-Schlüssel zu erhalten.", + "provider.connect.oauth.code.visit.prefix": "Besuchen Sie ", + "provider.connect.oauth.code.visit.link": "diesen Link", + "provider.connect.oauth.code.visit.suffix": + ", um Ihren Autorisierungscode zu erhalten, Ihr Konto zu verbinden und {{provider}} Modelle in OpenCode zu nutzen.", + "provider.connect.oauth.code.label": "{{method}} Autorisierungscode", + "provider.connect.oauth.code.placeholder": "Autorisierungscode", + "provider.connect.oauth.code.required": "Autorisierungscode ist erforderlich", + "provider.connect.oauth.code.invalid": "Ungültiger Autorisierungscode", + "provider.connect.oauth.auto.visit.prefix": "Besuchen Sie ", + "provider.connect.oauth.auto.visit.link": "diesen Link", + "provider.connect.oauth.auto.visit.suffix": + " und geben Sie den untenstehenden Code ein, um Ihr Konto zu verbinden und {{provider}} Modelle in OpenCode zu nutzen.", + "provider.connect.oauth.auto.confirmationCode": "Bestätigungscode", + "provider.connect.toast.connected.title": "{{provider}} verbunden", + "provider.connect.toast.connected.description": "{{provider}} Modelle sind jetzt verfügbar.", + + "model.tag.free": "Kostenlos", + "model.tag.latest": "Neueste", + + "common.search.placeholder": "Suchen", + "common.goBack": "Zurück", + "common.loading": "Laden", + "common.cancel": "Abbrechen", + "common.submit": "Absenden", + "common.save": "Speichern", + "common.saving": "Speichert...", + "common.default": "Standard", + "common.attachment": "Anhang", + + "prompt.placeholder.shell": "Shell-Befehl eingeben...", + "prompt.placeholder.normal": 'Fragen Sie alles... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc zum Verlassen", + + "prompt.example.1": "Ein TODO in der Codebasis beheben", + "prompt.example.2": "Was ist der Tech-Stack dieses Projekts?", + "prompt.example.3": "Fehlerhafte Tests beheben", + "prompt.example.4": "Erkläre, wie die Authentifizierung funktioniert", + "prompt.example.5": "Sicherheitslücken finden und beheben", + "prompt.example.6": "Unit-Tests für den Benutzerdienst hinzufügen", + "prompt.example.7": "Diese Funktion lesbarer gestalten", + "prompt.example.8": "Was bedeutet dieser Fehler?", + "prompt.example.9": "Hilf mir, dieses Problem zu debuggen", + "prompt.example.10": "API-Dokumentation generieren", + "prompt.example.11": "Datenbankabfragen optimieren", + "prompt.example.12": "Eingabevalidierung hinzufügen", + "prompt.example.13": "Neue Komponente erstellen für...", + "prompt.example.14": "Wie deploye ich dieses Projekt?", + "prompt.example.15": "Meinen Code auf Best Practices überprüfen", + "prompt.example.16": "Fehlerbehandlung zu dieser Funktion hinzufügen", + "prompt.example.17": "Erkläre dieses Regex-Muster", + "prompt.example.18": "Dies in TypeScript konvertieren", + "prompt.example.19": "Logging in der gesamten Codebasis hinzufügen", + "prompt.example.20": "Welche Abhängigkeiten sind veraltet?", + "prompt.example.21": "Hilf mir, ein Migrationsskript zu schreiben", + "prompt.example.22": "Caching für diesen Endpunkt implementieren", + "prompt.example.23": "Paginierung zu dieser Liste hinzufügen", + "prompt.example.24": "CLI-Befehl erstellen für...", + "prompt.example.25": "Wie funktionieren Umgebungsvariablen hier?", + + "prompt.popover.emptyResults": "Keine passenden Ergebnisse", + "prompt.popover.emptyCommands": "Keine passenden Befehle", + "prompt.dropzone.label": "Bilder oder PDFs hier ablegen", + "prompt.slash.badge.custom": "benutzerdefiniert", + "prompt.context.active": "aktiv", + "prompt.context.includeActiveFile": "Aktive Datei einbeziehen", + "prompt.context.removeActiveFile": "Aktive Datei aus dem Kontext entfernen", + "prompt.context.removeFile": "Datei aus dem Kontext entfernen", + "prompt.action.attachFile": "Datei anhängen", + "prompt.attachment.remove": "Anhang entfernen", + "prompt.action.send": "Senden", + "prompt.action.stop": "Stopp", + + "prompt.toast.pasteUnsupported.title": "Nicht unterstütztes Einfügen", + "prompt.toast.pasteUnsupported.description": "Hier können nur Bilder oder PDFs eingefügt werden.", + "prompt.toast.modelAgentRequired.title": "Wählen Sie einen Agenten und ein Modell", + "prompt.toast.modelAgentRequired.description": + "Wählen Sie einen Agenten und ein Modell, bevor Sie eine Eingabe senden.", + "prompt.toast.worktreeCreateFailed.title": "Worktree konnte nicht erstellt werden", + "prompt.toast.sessionCreateFailed.title": "Sitzung konnte nicht erstellt werden", + "prompt.toast.shellSendFailed.title": "Shell-Befehl konnte nicht gesendet werden", + "prompt.toast.commandSendFailed.title": "Befehl konnte nicht gesendet werden", + "prompt.toast.promptSendFailed.title": "Eingabe konnte nicht gesendet werden", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} von {{total}} aktiviert", + "dialog.mcp.empty": "Keine MCPs konfiguriert", + + "mcp.status.connected": "verbunden", + "mcp.status.failed": "fehlgeschlagen", + "mcp.status.needs_auth": "benötigt Authentifizierung", + "mcp.status.disabled": "deaktiviert", + + "dialog.fork.empty": "Keine Nachrichten zum Abzweigen vorhanden", + + "dialog.directory.search.placeholder": "Ordner durchsuchen", + "dialog.directory.empty": "Keine Ordner gefunden", + + "dialog.server.title": "Server", + "dialog.server.description": "Wechseln Sie den OpenCode-Server, mit dem sich diese App verbindet.", + "dialog.server.search.placeholder": "Server durchsuchen", + "dialog.server.empty": "Noch keine Server", + "dialog.server.add.title": "Server hinzufügen", + "dialog.server.add.url": "Server-URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Verbindung zum Server fehlgeschlagen", + "dialog.server.add.checking": "Prüfen...", + "dialog.server.add.button": "Hinzufügen", + "dialog.server.default.title": "Standardserver", + "dialog.server.default.description": + "Beim App-Start mit diesem Server verbinden, anstatt einen lokalen Server zu starten. Erfordert Neustart.", + "dialog.server.default.none": "Kein Server ausgewählt", + "dialog.server.default.set": "Aktuellen Server als Standard setzen", + "dialog.server.default.clear": "Löschen", + "dialog.server.action.remove": "Server entfernen", + + "dialog.project.edit.title": "Projekt bearbeiten", + "dialog.project.edit.name": "Name", + "dialog.project.edit.icon": "Icon", + "dialog.project.edit.icon.alt": "Projekt-Icon", + "dialog.project.edit.icon.hint": "Klicken oder Bild ziehen", + "dialog.project.edit.icon.recommended": "Empfohlen: 128x128px", + "dialog.project.edit.color": "Farbe", + "dialog.project.edit.color.select": "{{color}}-Farbe auswählen", + + "context.breakdown.title": "Kontext-Aufschlüsselung", + "context.breakdown.note": + 'Ungefähre Aufschlüsselung der Eingabe-Token. "Andere" beinhaltet Werkzeugdefinitionen und Overhead.', + "context.breakdown.system": "System", + "context.breakdown.user": "Benutzer", + "context.breakdown.assistant": "Assistent", + "context.breakdown.tool": "Werkzeugaufrufe", + "context.breakdown.other": "Andere", + + "context.systemPrompt.title": "System-Prompt", + "context.rawMessages.title": "Rohdaten der Nachrichten", + + "context.stats.session": "Sitzung", + "context.stats.messages": "Nachrichten", + "context.stats.provider": "Anbieter", + "context.stats.model": "Modell", + "context.stats.limit": "Kontextlimit", + "context.stats.totalTokens": "Gesamt-Token", + "context.stats.usage": "Nutzung", + "context.stats.inputTokens": "Eingabe-Token", + "context.stats.outputTokens": "Ausgabe-Token", + "context.stats.reasoningTokens": "Reasoning-Token", + "context.stats.cacheTokens": "Cache-Token (lesen/schreiben)", + "context.stats.userMessages": "Benutzernachrichten", + "context.stats.assistantMessages": "Assistentennachrichten", + "context.stats.totalCost": "Gesamtkosten", + "context.stats.sessionCreated": "Sitzung erstellt", + "context.stats.lastActivity": "Letzte Aktivität", + + "context.usage.tokens": "Token", + "context.usage.usage": "Nutzung", + "context.usage.cost": "Kosten", + "context.usage.clickToView": "Klicken, um Kontext anzuzeigen", + "context.usage.view": "Kontextnutzung anzeigen", + + "language.en": "Englisch", + "language.zh": "Chinesisch (Vereinfacht)", + "language.zht": "Chinesisch (Traditionell)", + "language.ko": "Koreanisch", + "language.de": "Deutsch", + "language.es": "Spanisch", + "language.fr": "Französisch", + "language.ja": "Japanisch", + "language.da": "Dänisch", + "language.ru": "Russisch", + "language.pl": "Polnisch", + "language.ar": "Arabisch", + "language.no": "Norwegisch", + "language.br": "Portugiesisch (Brasilien)", + + "toast.language.title": "Sprache", + "toast.language.description": "Zu {{language}} gewechselt", + + "toast.theme.title": "Thema gewechselt", + "toast.scheme.title": "Farbschema", + + "toast.permissions.autoaccept.on.title": "Änderungen werden automatisch akzeptiert", + "toast.permissions.autoaccept.on.description": "Bearbeitungs- und Schreibrechte werden automatisch genehmigt", + "toast.permissions.autoaccept.off.title": "Automatische Annahme von Änderungen gestoppt", + "toast.permissions.autoaccept.off.description": "Bearbeitungs- und Schreibrechte erfordern Genehmigung", + + "toast.model.none.title": "Kein Modell ausgewählt", + "toast.model.none.description": "Verbinden Sie einen Anbieter, um diese Sitzung zusammenzufassen", + + "toast.file.loadFailed.title": "Datei konnte nicht geladen werden", + + "toast.session.share.copyFailed.title": "URL konnte nicht in die Zwischenablage kopiert werden", + "toast.session.share.success.title": "Sitzung geteilt", + "toast.session.share.success.description": "Teilen-URL in die Zwischenablage kopiert!", + "toast.session.share.failed.title": "Sitzung konnte nicht geteilt werden", + "toast.session.share.failed.description": "Beim Teilen der Sitzung ist ein Fehler aufgetreten", + + "toast.session.unshare.success.title": "Teilen der Sitzung aufgehoben", + "toast.session.unshare.success.description": "Teilen der Sitzung erfolgreich aufgehoben!", + "toast.session.unshare.failed.title": "Aufheben des Teilens fehlgeschlagen", + "toast.session.unshare.failed.description": "Beim Aufheben des Teilens ist ein Fehler aufgetreten", + + "toast.session.listFailed.title": "Sitzungen für {{project}} konnten nicht geladen werden", + + "toast.update.title": "Update verfügbar", + "toast.update.description": "Eine neue Version von OpenCode ({{version}}) ist zur Installation verfügbar.", + "toast.update.action.installRestart": "Installieren und neu starten", + "toast.update.action.notYet": "Noch nicht", + + "error.page.title": "Etwas ist schiefgelaufen", + "error.page.description": "Beim Laden der Anwendung ist ein Fehler aufgetreten.", + "error.page.details.label": "Fehlerdetails", + "error.page.action.restart": "Neustart", + "error.page.action.checking": "Prüfen...", + "error.page.action.checkUpdates": "Nach Updates suchen", + "error.page.action.updateTo": "Auf {{version}} aktualisieren", + "error.page.report.prefix": "Bitte melden Sie diesen Fehler dem OpenCode-Team", + "error.page.report.discord": "auf Discord", + "error.page.version": "Version: {{version}}", + + "error.dev.rootNotFound": + "Wurzelelement nicht gefunden. Haben Sie vergessen, es in Ihre index.html aufzunehmen? Oder wurde das id-Attribut falsch geschrieben?", + + "error.globalSync.connectFailed": "Verbindung zum Server fehlgeschlagen. Läuft ein Server unter `{{url}}`?", + + "error.chain.unknown": "Unbekannter Fehler", + "error.chain.causedBy": "Verursacht durch:", + "error.chain.apiError": "API-Fehler", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Wiederholbar: {{retryable}}", + "error.chain.responseBody": "Antwort-Body:\n{{body}}", + "error.chain.didYouMean": "Meinten Sie: {{suggestions}}", + "error.chain.modelNotFound": "Modell nicht gefunden: {{provider}}/{{model}}", + "error.chain.checkConfig": "Überprüfen Sie Ihre Konfiguration (opencode.json) auf Anbieter-/Modellnamen", + "error.chain.mcpFailed": + 'MCP-Server "{{name}}" fehlgeschlagen. Hinweis: OpenCode unterstützt noch keine MCP-Authentifizierung.', + "error.chain.providerAuthFailed": "Anbieter-Authentifizierung fehlgeschlagen ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Anbieter "{{provider}}" konnte nicht initialisiert werden. Überprüfen Sie Anmeldeinformationen und Konfiguration.', + "error.chain.configJsonInvalid": "Konfigurationsdatei unter {{path}} ist kein gültiges JSON(C)", + "error.chain.configJsonInvalidWithMessage": + "Konfigurationsdatei unter {{path}} ist kein gültiges JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Verzeichnis "{{dir}}" in {{path}} ist ungültig. Benennen Sie das Verzeichnis in "{{suggestion}}" um oder entfernen Sie es. Dies ist ein häufiger Tippfehler.', + "error.chain.configFrontmatterError": "Frontmatter in {{path}} konnte nicht geparst werden:\n{{message}}", + "error.chain.configInvalid": "Konfigurationsdatei unter {{path}} ist ungültig", + "error.chain.configInvalidWithMessage": "Konfigurationsdatei unter {{path}} ist ungültig: {{message}}", + + "notification.permission.title": "Berechtigung erforderlich", + "notification.permission.description": "{{sessionTitle}} in {{projectName}} benötigt Berechtigung", + "notification.question.title": "Frage", + "notification.question.description": "{{sessionTitle}} in {{projectName}} hat eine Frage", + "notification.action.goToSession": "Zur Sitzung gehen", + + "notification.session.responseReady.title": "Antwort bereit", + "notification.session.error.title": "Sitzungsfehler", + "notification.session.error.fallbackDescription": "Ein Fehler ist aufgetreten", + + "home.recentProjects": "Letzte Projekte", + "home.empty.title": "Keine letzten Projekte", + "home.empty.description": "Starten Sie, indem Sie ein lokales Projekt öffnen", + + "session.tab.session": "Sitzung", + "session.tab.review": "Überprüfung", + "session.tab.context": "Kontext", + "session.panel.reviewAndFiles": "Überprüfung und Dateien", + "session.review.filesChanged": "{{count}} Dateien geändert", + "session.review.loadingChanges": "Lade Änderungen...", + "session.review.empty": "Noch keine Änderungen in dieser Sitzung", + "session.messages.renderEarlier": "Frühere Nachrichten rendern", + "session.messages.loadingEarlier": "Lade frühere Nachrichten...", + "session.messages.loadEarlier": "Frühere Nachrichten laden", + "session.messages.loading": "Lade Nachrichten...", + + "session.context.addToContext": "{{selection}} zum Kontext hinzufügen", + + "session.new.worktree.main": "Haupt-Branch", + "session.new.worktree.mainWithBranch": "Haupt-Branch ({{branch}})", + "session.new.worktree.create": "Neuen Worktree erstellen", + "session.new.lastModified": "Zuletzt geändert", + + "session.header.search.placeholder": "{{project}} durchsuchen", + "session.header.searchFiles": "Dateien suchen", + + "session.share.popover.title": "Im Web veröffentlichen", + "session.share.popover.description.shared": + "Diese Sitzung ist öffentlich im Web. Sie ist für jeden mit dem Link zugänglich.", + "session.share.popover.description.unshared": + "Sitzung öffentlich im Web teilen. Sie wird für jeden mit dem Link zugänglich sein.", + "session.share.action.share": "Teilen", + "session.share.action.publish": "Veröffentlichen", + "session.share.action.publishing": "Veröffentliche...", + "session.share.action.unpublish": "Veröffentlichung aufheben", + "session.share.action.unpublishing": "Hebe Veröffentlichung auf...", + "session.share.action.view": "Ansehen", + "session.share.copy.copied": "Kopiert", + "session.share.copy.copyLink": "Link kopieren", + + "lsp.tooltip.none": "Keine LSP-Server", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Lade Prompt...", + "terminal.loading": "Lade Terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Terminal schließen", + + "common.closeTab": "Tab schließen", + "common.dismiss": "Verwerfen", + "common.requestFailed": "Anfrage fehlgeschlagen", + "common.moreOptions": "Weitere Optionen", + "common.learnMore": "Mehr erfahren", + "common.rename": "Umbenennen", + "common.reset": "Zurücksetzen", + "common.archive": "Archivieren", + "common.delete": "Löschen", + "common.close": "Schließen", + "common.edit": "Bearbeiten", + "common.loadMore": "Mehr laden", + + "sidebar.nav.projectsAndSessions": "Projekte und Sitzungen", + "sidebar.settings": "Einstellungen", + "sidebar.help": "Hilfe", + "sidebar.workspaces.enable": "Arbeitsbereiche aktivieren", + "sidebar.workspaces.disable": "Arbeitsbereiche deaktivieren", + "sidebar.gettingStarted.title": "Erste Schritte", + "sidebar.gettingStarted.line1": "OpenCode enthält kostenlose Modelle, damit Sie sofort loslegen können.", + "sidebar.gettingStarted.line2": + "Verbinden Sie einen beliebigen Anbieter, um Modelle wie Claude, GPT, Gemini usw. zu nutzen.", + "sidebar.project.recentSessions": "Letzte Sitzungen", + "sidebar.project.viewAllSessions": "Alle Sitzungen anzeigen", + + "settings.section.desktop": "Desktop", + "settings.tab.general": "Allgemein", + "settings.tab.shortcuts": "Tastenkombinationen", + + "settings.general.section.appearance": "Erscheinungsbild", + "settings.general.section.notifications": "Systembenachrichtigungen", + "settings.general.section.sounds": "Soundeffekte", + + "settings.general.row.language.title": "Sprache", + "settings.general.row.language.description": "Die Anzeigesprache für OpenCode ändern", + "settings.general.row.appearance.title": "Erscheinungsbild", + "settings.general.row.appearance.description": "Anpassen, wie OpenCode auf Ihrem Gerät aussieht", + "settings.general.row.theme.title": "Thema", + "settings.general.row.theme.description": "Das Thema von OpenCode anpassen.", + "settings.general.row.font.title": "Schriftart", + "settings.general.row.font.description": "Die in Codeblöcken verwendete Monospace-Schriftart anpassen", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Systembenachrichtigung anzeigen, wenn der Agent fertig ist oder Aufmerksamkeit benötigt", + "settings.general.notifications.permissions.title": "Berechtigungen", + "settings.general.notifications.permissions.description": + "Systembenachrichtigung anzeigen, wenn eine Berechtigung erforderlich ist", + "settings.general.notifications.errors.title": "Fehler", + "settings.general.notifications.errors.description": "Systembenachrichtigung anzeigen, wenn ein Fehler auftritt", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Ton abspielen, wenn der Agent fertig ist oder Aufmerksamkeit benötigt", + "settings.general.sounds.permissions.title": "Berechtigungen", + "settings.general.sounds.permissions.description": "Ton abspielen, wenn eine Berechtigung erforderlich ist", + "settings.general.sounds.errors.title": "Fehler", + "settings.general.sounds.errors.description": "Ton abspielen, wenn ein Fehler auftritt", + + "settings.shortcuts.title": "Tastenkombinationen", + "settings.shortcuts.reset.button": "Auf Standard zurücksetzen", + "settings.shortcuts.reset.toast.title": "Tastenkombinationen zurückgesetzt", + "settings.shortcuts.reset.toast.description": "Die Tastenkombinationen wurden auf die Standardwerte zurückgesetzt.", + "settings.shortcuts.conflict.title": "Tastenkombination bereits in Verwendung", + "settings.shortcuts.conflict.description": "{{keybind}} ist bereits {{titles}} zugewiesen.", + "settings.shortcuts.unassigned": "Nicht zugewiesen", + "settings.shortcuts.pressKeys": "Tasten drücken", + "settings.shortcuts.search.placeholder": "Tastenkürzel suchen", + "settings.shortcuts.search.empty": "Keine Tastenkürzel gefunden", + + "settings.shortcuts.group.general": "Allgemein", + "settings.shortcuts.group.session": "Sitzung", + "settings.shortcuts.group.navigation": "Navigation", + "settings.shortcuts.group.modelAndAgent": "Modell und Agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Anbieter", + "settings.providers.description": "Anbietereinstellungen können hier konfiguriert werden.", + "settings.models.title": "Modelle", + "settings.models.description": "Modelleinstellungen können hier konfiguriert werden.", + "settings.agents.title": "Agenten", + "settings.agents.description": "Agenteneinstellungen können hier konfiguriert werden.", + "settings.commands.title": "Befehle", + "settings.commands.description": "Befehlseinstellungen können hier konfiguriert werden.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP-Einstellungen können hier konfiguriert werden.", + + "settings.permissions.title": "Berechtigungen", + "settings.permissions.description": "Steuern Sie, welche Tools der Server standardmäßig verwenden darf.", + "settings.permissions.section.tools": "Tools", + "settings.permissions.toast.updateFailed.title": "Berechtigungen konnten nicht aktualisiert werden", + + "settings.permissions.action.allow": "Erlauben", + "settings.permissions.action.ask": "Fragen", + "settings.permissions.action.deny": "Verweigern", + + "settings.permissions.tool.read.title": "Lesen", + "settings.permissions.tool.read.description": "Lesen einer Datei (stimmt mit dem Dateipfad überein)", + "settings.permissions.tool.edit.title": "Bearbeiten", + "settings.permissions.tool.edit.description": + "Dateien ändern, einschließlich Bearbeitungen, Schreibvorgängen, Patches und Mehrfachbearbeitungen", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Dateien mithilfe von Glob-Mustern abgleichen", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Dateiinhalte mit regulären Ausdrücken durchsuchen", + "settings.permissions.tool.list.title": "Auflisten", + "settings.permissions.tool.list.description": "Dateien in einem Verzeichnis auflisten", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Shell-Befehle ausführen", + "settings.permissions.tool.task.title": "Aufgabe", + "settings.permissions.tool.task.description": "Unteragenten starten", + "settings.permissions.tool.skill.title": "Fähigkeit", + "settings.permissions.tool.skill.description": "Eine Fähigkeit nach Namen laden", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Language-Server-Abfragen ausführen", + "settings.permissions.tool.todoread.title": "Todo lesen", + "settings.permissions.tool.todoread.description": "Die Todo-Liste lesen", + "settings.permissions.tool.todowrite.title": "Todo schreiben", + "settings.permissions.tool.todowrite.description": "Die Todo-Liste aktualisieren", + "settings.permissions.tool.webfetch.title": "Web-Abruf", + "settings.permissions.tool.webfetch.description": "Inhalt von einer URL abrufen", + "settings.permissions.tool.websearch.title": "Web-Suche", + "settings.permissions.tool.websearch.description": "Das Web durchsuchen", + "settings.permissions.tool.codesearch.title": "Code-Suche", + "settings.permissions.tool.codesearch.description": "Code im Web durchsuchen", + "settings.permissions.tool.external_directory.title": "Externes Verzeichnis", + "settings.permissions.tool.external_directory.description": "Zugriff auf Dateien außerhalb des Projektverzeichnisses", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "Wiederholte Tool-Aufrufe mit identischer Eingabe erkennen", + + "session.delete.failed.title": "Sitzung konnte nicht gelöscht werden", + "session.delete.title": "Sitzung löschen", + "session.delete.confirm": 'Sitzung "{{name}}" löschen?', + "session.delete.button": "Sitzung löschen", + + "workspace.new": "Neuer Arbeitsbereich", + "workspace.type.local": "lokal", + "workspace.type.sandbox": "Sandbox", + "workspace.create.failed.title": "Arbeitsbereich konnte nicht erstellt werden", + "workspace.delete.failed.title": "Arbeitsbereich konnte nicht gelöscht werden", + "workspace.resetting.title": "Arbeitsbereich wird zurückgesetzt", + "workspace.resetting.description": "Dies kann eine Minute dauern.", + "workspace.reset.failed.title": "Arbeitsbereich konnte nicht zurückgesetzt werden", + "workspace.reset.success.title": "Arbeitsbereich zurückgesetzt", + "workspace.reset.success.description": "Der Arbeitsbereich entspricht jetzt dem Standard-Branch.", + "workspace.status.checking": "Suche nach nicht zusammengeführten Änderungen...", + "workspace.status.error": "Git-Status konnte nicht überprüft werden.", + "workspace.status.clean": "Keine nicht zusammengeführten Änderungen erkannt.", + "workspace.status.dirty": "Nicht zusammengeführte Änderungen in diesem Arbeitsbereich erkannt.", + "workspace.delete.title": "Arbeitsbereich löschen", + "workspace.delete.confirm": 'Arbeitsbereich "{{name}}" löschen?', + "workspace.delete.button": "Arbeitsbereich löschen", + "workspace.reset.title": "Arbeitsbereich zurücksetzen", + "workspace.reset.confirm": 'Arbeitsbereich "{{name}}" zurücksetzen?', + "workspace.reset.button": "Arbeitsbereich zurücksetzen", + "workspace.reset.archived.none": "Keine aktiven Sitzungen werden archiviert.", + "workspace.reset.archived.one": "1 Sitzung wird archiviert.", + "workspace.reset.archived.many": "{{count}} Sitzungen werden archiviert.", + "workspace.reset.note": "Dadurch wird der Arbeitsbereich auf den Standard-Branch zurückgesetzt.", +} satisfies Partial> diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts new file mode 100644 index 00000000000..ed00ff18be7 --- /dev/null +++ b/packages/app/src/i18n/en.ts @@ -0,0 +1,661 @@ +export const dict = { + "command.category.suggested": "Suggested", + "command.category.view": "View", + "command.category.project": "Project", + "command.category.provider": "Provider", + "command.category.server": "Server", + "command.category.session": "Session", + "command.category.theme": "Theme", + "command.category.language": "Language", + "command.category.file": "File", + "command.category.terminal": "Terminal", + "command.category.model": "Model", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Permissions", + "command.category.workspace": "Workspace", + "command.category.settings": "Settings", + + "theme.scheme.system": "System", + "theme.scheme.light": "Light", + "theme.scheme.dark": "Dark", + + "command.sidebar.toggle": "Toggle sidebar", + "command.project.open": "Open project", + "command.provider.connect": "Connect provider", + "command.server.switch": "Switch server", + "command.settings.open": "Open settings", + "command.session.previous": "Previous session", + "command.session.next": "Next session", + "command.session.archive": "Archive session", + + "command.palette": "Command palette", + + "command.theme.cycle": "Cycle theme", + "command.theme.set": "Use theme: {{theme}}", + "command.theme.scheme.cycle": "Cycle color scheme", + "command.theme.scheme.set": "Use color scheme: {{scheme}}", + + "command.language.cycle": "Cycle language", + "command.language.set": "Use language: {{language}}", + + "command.session.new": "New session", + "command.file.open": "Open file", + "command.file.open.description": "Search files and commands", + "command.terminal.toggle": "Toggle terminal", + "command.review.toggle": "Toggle review", + "command.terminal.new": "New terminal", + "command.terminal.new.description": "Create a new terminal tab", + "command.steps.toggle": "Toggle steps", + "command.steps.toggle.description": "Show or hide steps for the current message", + "command.message.previous": "Previous message", + "command.message.previous.description": "Go to the previous user message", + "command.message.next": "Next message", + "command.message.next.description": "Go to the next user message", + "command.model.choose": "Choose model", + "command.model.choose.description": "Select a different model", + "command.mcp.toggle": "Toggle MCPs", + "command.mcp.toggle.description": "Toggle MCPs", + "command.agent.cycle": "Cycle agent", + "command.agent.cycle.description": "Switch to the next agent", + "command.agent.cycle.reverse": "Cycle agent backwards", + "command.agent.cycle.reverse.description": "Switch to the previous agent", + "command.model.variant.cycle": "Cycle thinking effort", + "command.model.variant.cycle.description": "Switch to the next effort level", + "command.permissions.autoaccept.enable": "Auto-accept edits", + "command.permissions.autoaccept.disable": "Stop auto-accepting edits", + "command.session.undo": "Undo", + "command.session.undo.description": "Undo the last message", + "command.session.redo": "Redo", + "command.session.redo.description": "Redo the last undone message", + "command.session.compact": "Compact session", + "command.session.compact.description": "Summarize the session to reduce context size", + "command.session.fork": "Fork from message", + "command.session.fork.description": "Create a new session from a previous message", + "command.session.share": "Share session", + "command.session.share.description": "Share this session and copy the URL to clipboard", + "command.session.unshare": "Unshare session", + "command.session.unshare.description": "Stop sharing this session", + + "palette.search.placeholder": "Search files and commands", + "palette.empty": "No results found", + "palette.group.commands": "Commands", + "palette.group.files": "Files", + + "dialog.provider.search.placeholder": "Search providers", + "dialog.provider.empty": "No providers found", + "dialog.provider.group.popular": "Popular", + "dialog.provider.group.other": "Other", + "dialog.provider.tag.recommended": "Recommended", + "dialog.provider.anthropic.note": "Connect with Claude Pro/Max or API key", + + "dialog.model.select.title": "Select model", + "dialog.model.search.placeholder": "Search models", + "dialog.model.empty": "No model results", + "dialog.model.manage": "Manage models", + "dialog.model.manage.description": "Customize which models appear in the model selector.", + + "dialog.model.unpaid.freeModels.title": "Free models provided by OpenCode", + "dialog.model.unpaid.addMore.title": "Add more models from popular providers", + + "dialog.provider.viewAll": "View all providers", + + "provider.connect.title": "Connect {{provider}}", + "provider.connect.title.anthropicProMax": "Login with Claude Pro/Max", + "provider.connect.selectMethod": "Select login method for {{provider}}.", + "provider.connect.method.apiKey": "API key", + "provider.connect.status.inProgress": "Authorization in progress...", + "provider.connect.status.waiting": "Waiting for authorization...", + "provider.connect.status.failed": "Authorization failed: {{error}}", + "provider.connect.apiKey.description": + "Enter your {{provider}} API key to connect your account and use {{provider}} models in OpenCode.", + "provider.connect.apiKey.label": "{{provider}} API key", + "provider.connect.apiKey.placeholder": "API key", + "provider.connect.apiKey.required": "API key is required", + "provider.connect.opencodeZen.line1": + "OpenCode Zen gives you access to a curated set of reliable optimized models for coding agents.", + "provider.connect.opencodeZen.line2": + "With a single API key you'll get access to models such as Claude, GPT, Gemini, GLM and more.", + "provider.connect.opencodeZen.visit.prefix": "Visit ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " to collect your API key.", + "provider.connect.oauth.code.visit.prefix": "Visit ", + "provider.connect.oauth.code.visit.link": "this link", + "provider.connect.oauth.code.visit.suffix": + " to collect your authorization code to connect your account and use {{provider}} models in OpenCode.", + "provider.connect.oauth.code.label": "{{method}} authorization code", + "provider.connect.oauth.code.placeholder": "Authorization code", + "provider.connect.oauth.code.required": "Authorization code is required", + "provider.connect.oauth.code.invalid": "Invalid authorization code", + "provider.connect.oauth.auto.visit.prefix": "Visit ", + "provider.connect.oauth.auto.visit.link": "this link", + "provider.connect.oauth.auto.visit.suffix": + " and enter the code below to connect your account and use {{provider}} models in OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Confirmation code", + "provider.connect.toast.connected.title": "{{provider}} connected", + "provider.connect.toast.connected.description": "{{provider}} models are now available to use.", + + "model.tag.free": "Free", + "model.tag.latest": "Latest", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "text", + "model.input.image": "image", + "model.input.audio": "audio", + "model.input.video": "video", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Allows: {{inputs}}", + "model.tooltip.reasoning.allowed": "Allows reasoning", + "model.tooltip.reasoning.none": "No reasoning", + "model.tooltip.context": "Context limit {{limit}}", + + "common.search.placeholder": "Search", + "common.goBack": "Go back", + "common.loading": "Loading", + "common.loading.ellipsis": "...", + "common.cancel": "Cancel", + "common.submit": "Submit", + "common.save": "Save", + "common.saving": "Saving...", + "common.default": "Default", + "common.attachment": "attachment", + + "prompt.placeholder.shell": "Enter shell command...", + "prompt.placeholder.normal": 'Ask anything... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc to exit", + + "prompt.example.1": "Fix a TODO in the codebase", + "prompt.example.2": "What is the tech stack of this project?", + "prompt.example.3": "Fix broken tests", + "prompt.example.4": "Explain how authentication works", + "prompt.example.5": "Find and fix security vulnerabilities", + "prompt.example.6": "Add unit tests for the user service", + "prompt.example.7": "Refactor this function to be more readable", + "prompt.example.8": "What does this error mean?", + "prompt.example.9": "Help me debug this issue", + "prompt.example.10": "Generate API documentation", + "prompt.example.11": "Optimize database queries", + "prompt.example.12": "Add input validation", + "prompt.example.13": "Create a new component for...", + "prompt.example.14": "How do I deploy this project?", + "prompt.example.15": "Review my code for best practices", + "prompt.example.16": "Add error handling to this function", + "prompt.example.17": "Explain this regex pattern", + "prompt.example.18": "Convert this to TypeScript", + "prompt.example.19": "Add logging throughout the codebase", + "prompt.example.20": "What dependencies are outdated?", + "prompt.example.21": "Help me write a migration script", + "prompt.example.22": "Implement caching for this endpoint", + "prompt.example.23": "Add pagination to this list", + "prompt.example.24": "Create a CLI command for...", + "prompt.example.25": "How do environment variables work here?", + + "prompt.popover.emptyResults": "No matching results", + "prompt.popover.emptyCommands": "No matching commands", + "prompt.dropzone.label": "Drop images or PDFs here", + "prompt.slash.badge.custom": "custom", + "prompt.context.active": "active", + "prompt.context.includeActiveFile": "Include active file", + "prompt.context.removeActiveFile": "Remove active file from context", + "prompt.context.removeFile": "Remove file from context", + "prompt.action.attachFile": "Attach file", + "prompt.attachment.remove": "Remove attachment", + "prompt.action.send": "Send", + "prompt.action.stop": "Stop", + + "prompt.toast.pasteUnsupported.title": "Unsupported paste", + "prompt.toast.pasteUnsupported.description": "Only images or PDFs can be pasted here.", + "prompt.toast.modelAgentRequired.title": "Select an agent and model", + "prompt.toast.modelAgentRequired.description": "Choose an agent and model before sending a prompt.", + "prompt.toast.worktreeCreateFailed.title": "Failed to create worktree", + "prompt.toast.sessionCreateFailed.title": "Failed to create session", + "prompt.toast.shellSendFailed.title": "Failed to send shell command", + "prompt.toast.commandSendFailed.title": "Failed to send command", + "prompt.toast.promptSendFailed.title": "Failed to send prompt", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} of {{total}} enabled", + "dialog.mcp.empty": "No MCPs configured", + + "mcp.status.connected": "connected", + "mcp.status.failed": "failed", + "mcp.status.needs_auth": "needs auth", + "mcp.status.disabled": "disabled", + + "dialog.fork.empty": "No messages to fork from", + + "dialog.directory.search.placeholder": "Search folders", + "dialog.directory.empty": "No folders found", + + "dialog.server.title": "Servers", + "dialog.server.description": "Switch which OpenCode server this app connects to.", + "dialog.server.search.placeholder": "Search servers", + "dialog.server.empty": "No servers yet", + "dialog.server.add.title": "Add a server", + "dialog.server.add.url": "Server URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Could not connect to server", + "dialog.server.add.checking": "Checking...", + "dialog.server.add.button": "Add", + "dialog.server.default.title": "Default server", + "dialog.server.default.description": + "Connect to this server on app launch instead of starting a local server. Requires restart.", + "dialog.server.default.none": "No server selected", + "dialog.server.default.set": "Set current server as default", + "dialog.server.default.clear": "Clear", + "dialog.server.action.remove": "Remove server", + + "dialog.project.edit.title": "Edit project", + "dialog.project.edit.name": "Name", + "dialog.project.edit.icon": "Icon", + "dialog.project.edit.icon.alt": "Project icon", + "dialog.project.edit.icon.hint": "Click or drag an image", + "dialog.project.edit.icon.recommended": "Recommended: 128x128px", + "dialog.project.edit.color": "Color", + "dialog.project.edit.color.select": "Select {{color}} color", + "dialog.project.edit.worktree.startup": "Workspace startup script", + "dialog.project.edit.worktree.startup.description": "Runs after creating a new workspace (worktree).", + "dialog.project.edit.worktree.startup.placeholder": "e.g. bun install", + + "context.breakdown.title": "Context Breakdown", + "context.breakdown.note": 'Approximate breakdown of input tokens. "Other" includes tool definitions and overhead.', + "context.breakdown.system": "System", + "context.breakdown.user": "User", + "context.breakdown.assistant": "Assistant", + "context.breakdown.tool": "Tool Calls", + "context.breakdown.other": "Other", + + "context.systemPrompt.title": "System Prompt", + "context.rawMessages.title": "Raw messages", + + "context.stats.session": "Session", + "context.stats.messages": "Messages", + "context.stats.provider": "Provider", + "context.stats.model": "Model", + "context.stats.limit": "Context Limit", + "context.stats.totalTokens": "Total Tokens", + "context.stats.usage": "Usage", + "context.stats.inputTokens": "Input Tokens", + "context.stats.outputTokens": "Output Tokens", + "context.stats.reasoningTokens": "Reasoning Tokens", + "context.stats.cacheTokens": "Cache Tokens (read/write)", + "context.stats.userMessages": "User Messages", + "context.stats.assistantMessages": "Assistant Messages", + "context.stats.totalCost": "Total Cost", + "context.stats.sessionCreated": "Session Created", + "context.stats.lastActivity": "Last Activity", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Usage", + "context.usage.cost": "Cost", + "context.usage.clickToView": "Click to view context", + "context.usage.view": "View context usage", + + "language.en": "English", + "language.zh": "Chinese (Simplified)", + "language.zht": "Chinese (Traditional)", + "language.ko": "Korean", + "language.de": "German", + "language.es": "Spanish", + "language.fr": "French", + "language.ja": "Japanese", + "language.da": "Danish", + "language.ru": "Russian", + "language.pl": "Polish", + "language.ar": "Arabic", + "language.no": "Norwegian", + "language.br": "Portuguese (Brazil)", + + "toast.language.title": "Language", + "toast.language.description": "Switched to {{language}}", + + "toast.theme.title": "Theme switched", + "toast.scheme.title": "Color scheme", + + "toast.permissions.autoaccept.on.title": "Auto-accepting edits", + "toast.permissions.autoaccept.on.description": "Edit and write permissions will be automatically approved", + "toast.permissions.autoaccept.off.title": "Stopped auto-accepting edits", + "toast.permissions.autoaccept.off.description": "Edit and write permissions will require approval", + + "toast.model.none.title": "No model selected", + "toast.model.none.description": "Connect a provider to summarize this session", + + "toast.file.loadFailed.title": "Failed to load file", + + "toast.session.share.copyFailed.title": "Failed to copy URL to clipboard", + "toast.session.share.success.title": "Session shared", + "toast.session.share.success.description": "Share URL copied to clipboard!", + "toast.session.share.failed.title": "Failed to share session", + "toast.session.share.failed.description": "An error occurred while sharing the session", + + "toast.session.unshare.success.title": "Session unshared", + "toast.session.unshare.success.description": "Session unshared successfully!", + "toast.session.unshare.failed.title": "Failed to unshare session", + "toast.session.unshare.failed.description": "An error occurred while unsharing the session", + + "toast.session.listFailed.title": "Failed to load sessions for {{project}}", + + "toast.update.title": "Update available", + "toast.update.description": "A new version of OpenCode ({{version}}) is now available to install.", + "toast.update.action.installRestart": "Install and restart", + "toast.update.action.notYet": "Not yet", + + "error.page.title": "Something went wrong", + "error.page.description": "An error occurred while loading the application.", + "error.page.details.label": "Error Details", + "error.page.action.restart": "Restart", + "error.page.action.checking": "Checking...", + "error.page.action.checkUpdates": "Check for updates", + "error.page.action.updateTo": "Update to {{version}}", + "error.page.report.prefix": "Please report this error to the OpenCode team", + "error.page.report.discord": "on Discord", + "error.page.version": "Version: {{version}}", + + "error.dev.rootNotFound": + "Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?", + + "error.globalSync.connectFailed": "Could not connect to server. Is there a server running at `{{url}}`?", + + "error.chain.unknown": "Unknown error", + "error.chain.causedBy": "Caused by:", + "error.chain.apiError": "API error", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Retryable: {{retryable}}", + "error.chain.responseBody": "Response body:\n{{body}}", + "error.chain.didYouMean": "Did you mean: {{suggestions}}", + "error.chain.modelNotFound": "Model not found: {{provider}}/{{model}}", + "error.chain.checkConfig": "Check your config (opencode.json) provider/model names", + "error.chain.mcpFailed": 'MCP server "{{name}}" failed. Note, OpenCode does not support MCP authentication yet.', + "error.chain.providerAuthFailed": "Provider authentication failed ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Failed to initialize provider "{{provider}}". Check credentials and configuration.', + "error.chain.configJsonInvalid": "Config file at {{path}} is not valid JSON(C)", + "error.chain.configJsonInvalidWithMessage": "Config file at {{path}} is not valid JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Directory "{{dir}}" in {{path}} is not valid. Rename the directory to "{{suggestion}}" or remove it. This is a common typo.', + "error.chain.configFrontmatterError": "Failed to parse frontmatter in {{path}}:\n{{message}}", + "error.chain.configInvalid": "Config file at {{path}} is invalid", + "error.chain.configInvalidWithMessage": "Config file at {{path}} is invalid: {{message}}", + + "notification.permission.title": "Permission required", + "notification.permission.description": "{{sessionTitle}} in {{projectName}} needs permission", + "notification.question.title": "Question", + "notification.question.description": "{{sessionTitle}} in {{projectName}} has a question", + "notification.action.goToSession": "Go to session", + + "notification.session.responseReady.title": "Response ready", + "notification.session.error.title": "Session error", + "notification.session.error.fallbackDescription": "An error occurred", + + "home.recentProjects": "Recent projects", + "home.empty.title": "No recent projects", + "home.empty.description": "Get started by opening a local project", + + "session.tab.session": "Session", + "session.tab.review": "Review", + "session.tab.context": "Context", + "session.panel.reviewAndFiles": "Review and files", + "session.review.filesChanged": "{{count}} Files Changed", + "session.review.loadingChanges": "Loading changes...", + "session.review.empty": "No changes in this session yet", + "session.messages.renderEarlier": "Render earlier messages", + "session.messages.loadingEarlier": "Loading earlier messages...", + "session.messages.loadEarlier": "Load earlier messages", + "session.messages.loading": "Loading messages...", + "session.messages.jumpToLatest": "Jump to latest", + + "session.context.addToContext": "Add {{selection}} to context", + + "session.new.worktree.main": "Main branch", + "session.new.worktree.mainWithBranch": "Main branch ({{branch}})", + "session.new.worktree.create": "Create new worktree", + "session.new.lastModified": "Last modified", + + "session.header.search.placeholder": "Search {{project}}", + "session.header.searchFiles": "Search files", + + "session.share.popover.title": "Publish on web", + "session.share.popover.description.shared": + "This session is public on the web. It is accessible to anyone with the link.", + "session.share.popover.description.unshared": + "Share session publicly on the web. It will be accessible to anyone with the link.", + "session.share.action.share": "Share", + "session.share.action.publish": "Publish", + "session.share.action.publishing": "Publishing...", + "session.share.action.unpublish": "Unpublish", + "session.share.action.unpublishing": "Unpublishing...", + "session.share.action.view": "View", + "session.share.copy.copied": "Copied", + "session.share.copy.copyLink": "Copy link", + + "lsp.tooltip.none": "No LSP servers", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Loading prompt...", + "terminal.loading": "Loading terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Close terminal", + "terminal.connectionLost.title": "Connection Lost", + "terminal.connectionLost.description": + "The terminal connection was interrupted. This can happen when the server restarts.", + + "common.closeTab": "Close tab", + "common.dismiss": "Dismiss", + "common.requestFailed": "Request failed", + "common.moreOptions": "More options", + "common.learnMore": "Learn more", + "common.rename": "Rename", + "common.reset": "Reset", + "common.archive": "Archive", + "common.delete": "Delete", + "common.close": "Close", + "common.edit": "Edit", + "common.loadMore": "Load more", + "common.key.esc": "ESC", + + "sidebar.menu.toggle": "Toggle menu", + "sidebar.nav.projectsAndSessions": "Projects and sessions", + "sidebar.settings": "Settings", + "sidebar.help": "Help", + "sidebar.workspaces.enable": "Enable workspaces", + "sidebar.workspaces.disable": "Disable workspaces", + "sidebar.gettingStarted.title": "Getting started", + "sidebar.gettingStarted.line1": "OpenCode includes free models so you can start immediately.", + "sidebar.gettingStarted.line2": "Connect any provider to use models, inc. Claude, GPT, Gemini etc.", + "sidebar.project.recentSessions": "Recent sessions", + "sidebar.project.viewAllSessions": "View all sessions", + + "settings.section.desktop": "Desktop", + "settings.tab.general": "General", + "settings.tab.shortcuts": "Shortcuts", + + "settings.general.section.appearance": "Appearance", + "settings.general.section.notifications": "System notifications", + "settings.general.section.sounds": "Sound effects", + + "settings.general.row.language.title": "Language", + "settings.general.row.language.description": "Change the display language for OpenCode", + "settings.general.row.appearance.title": "Appearance", + "settings.general.row.appearance.description": "Customise how OpenCode looks on your device", + "settings.general.row.theme.title": "Theme", + "settings.general.row.theme.description": "Customise how OpenCode is themed.", + "settings.general.row.font.title": "Font", + "settings.general.row.font.description": "Customise the mono font used in code blocks", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "sound.option.alert01": "Alert 01", + "sound.option.alert02": "Alert 02", + "sound.option.alert03": "Alert 03", + "sound.option.alert04": "Alert 04", + "sound.option.alert05": "Alert 05", + "sound.option.alert06": "Alert 06", + "sound.option.alert07": "Alert 07", + "sound.option.alert08": "Alert 08", + "sound.option.alert09": "Alert 09", + "sound.option.alert10": "Alert 10", + "sound.option.bipbop01": "Bip-bop 01", + "sound.option.bipbop02": "Bip-bop 02", + "sound.option.bipbop03": "Bip-bop 03", + "sound.option.bipbop04": "Bip-bop 04", + "sound.option.bipbop05": "Bip-bop 05", + "sound.option.bipbop06": "Bip-bop 06", + "sound.option.bipbop07": "Bip-bop 07", + "sound.option.bipbop08": "Bip-bop 08", + "sound.option.bipbop09": "Bip-bop 09", + "sound.option.bipbop10": "Bip-bop 10", + "sound.option.staplebops01": "Staplebops 01", + "sound.option.staplebops02": "Staplebops 02", + "sound.option.staplebops03": "Staplebops 03", + "sound.option.staplebops04": "Staplebops 04", + "sound.option.staplebops05": "Staplebops 05", + "sound.option.staplebops06": "Staplebops 06", + "sound.option.staplebops07": "Staplebops 07", + "sound.option.nope01": "Nope 01", + "sound.option.nope02": "Nope 02", + "sound.option.nope03": "Nope 03", + "sound.option.nope04": "Nope 04", + "sound.option.nope05": "Nope 05", + "sound.option.nope06": "Nope 06", + "sound.option.nope07": "Nope 07", + "sound.option.nope08": "Nope 08", + "sound.option.nope09": "Nope 09", + "sound.option.nope10": "Nope 10", + "sound.option.nope11": "Nope 11", + "sound.option.nope12": "Nope 12", + "sound.option.yup01": "Yup 01", + "sound.option.yup02": "Yup 02", + "sound.option.yup03": "Yup 03", + "sound.option.yup04": "Yup 04", + "sound.option.yup05": "Yup 05", + "sound.option.yup06": "Yup 06", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Show system notification when the agent is complete or needs attention", + "settings.general.notifications.permissions.title": "Permissions", + "settings.general.notifications.permissions.description": "Show system notification when a permission is required", + "settings.general.notifications.errors.title": "Errors", + "settings.general.notifications.errors.description": "Show system notification when an error occurs", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Play sound when the agent is complete or needs attention", + "settings.general.sounds.permissions.title": "Permissions", + "settings.general.sounds.permissions.description": "Play sound when a permission is required", + "settings.general.sounds.errors.title": "Errors", + "settings.general.sounds.errors.description": "Play sound when an error occurs", + + "settings.shortcuts.title": "Keyboard shortcuts", + "settings.shortcuts.reset.button": "Reset to defaults", + "settings.shortcuts.reset.toast.title": "Shortcuts reset", + "settings.shortcuts.reset.toast.description": "Keyboard shortcuts have been reset to defaults.", + "settings.shortcuts.conflict.title": "Shortcut already in use", + "settings.shortcuts.conflict.description": "{{keybind}} is already assigned to {{titles}}.", + "settings.shortcuts.unassigned": "Unassigned", + "settings.shortcuts.pressKeys": "Press keys", + "settings.shortcuts.search.placeholder": "Search shortcuts", + "settings.shortcuts.search.empty": "No shortcuts found", + + "settings.shortcuts.group.general": "General", + "settings.shortcuts.group.session": "Session", + "settings.shortcuts.group.navigation": "Navigation", + "settings.shortcuts.group.modelAndAgent": "Model and agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Providers", + "settings.providers.description": "Provider settings will be configurable here.", + "settings.models.title": "Models", + "settings.models.description": "Model settings will be configurable here.", + "settings.agents.title": "Agents", + "settings.agents.description": "Agent settings will be configurable here.", + "settings.commands.title": "Commands", + "settings.commands.description": "Command settings will be configurable here.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP settings will be configurable here.", + + "settings.permissions.title": "Permissions", + "settings.permissions.description": "Control what tools the server can use by default.", + "settings.permissions.section.tools": "Tools", + "settings.permissions.toast.updateFailed.title": "Failed to update permissions", + + "settings.permissions.action.allow": "Allow", + "settings.permissions.action.ask": "Ask", + "settings.permissions.action.deny": "Deny", + + "settings.permissions.tool.read.title": "Read", + "settings.permissions.tool.read.description": "Reading a file (matches the file path)", + "settings.permissions.tool.edit.title": "Edit", + "settings.permissions.tool.edit.description": "Modify files, including edits, writes, patches, and multi-edits", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Match files using glob patterns", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Search file contents using regular expressions", + "settings.permissions.tool.list.title": "List", + "settings.permissions.tool.list.description": "List files within a directory", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Run shell commands", + "settings.permissions.tool.task.title": "Task", + "settings.permissions.tool.task.description": "Launch sub-agents", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "Load a skill by name", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Run language server queries", + "settings.permissions.tool.todoread.title": "Todo Read", + "settings.permissions.tool.todoread.description": "Read the todo list", + "settings.permissions.tool.todowrite.title": "Todo Write", + "settings.permissions.tool.todowrite.description": "Update the todo list", + "settings.permissions.tool.webfetch.title": "Web Fetch", + "settings.permissions.tool.webfetch.description": "Fetch content from a URL", + "settings.permissions.tool.websearch.title": "Web Search", + "settings.permissions.tool.websearch.description": "Search the web", + "settings.permissions.tool.codesearch.title": "Code Search", + "settings.permissions.tool.codesearch.description": "Search code on the web", + "settings.permissions.tool.external_directory.title": "External Directory", + "settings.permissions.tool.external_directory.description": "Access files outside the project directory", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "Detect repeated tool calls with identical input", + + "session.delete.failed.title": "Failed to delete session", + "session.delete.title": "Delete session", + "session.delete.confirm": 'Delete session "{{name}}"?', + "session.delete.button": "Delete session", + + "workspace.new": "New workspace", + "workspace.type.local": "local", + "workspace.type.sandbox": "sandbox", + "workspace.create.failed.title": "Failed to create workspace", + "workspace.delete.failed.title": "Failed to delete workspace", + "workspace.resetting.title": "Resetting workspace", + "workspace.resetting.description": "This may take a minute.", + "workspace.reset.failed.title": "Failed to reset workspace", + "workspace.reset.success.title": "Workspace reset", + "workspace.reset.success.description": "Workspace now matches the default branch.", + "workspace.status.checking": "Checking for unmerged changes...", + "workspace.status.error": "Unable to verify git status.", + "workspace.status.clean": "No unmerged changes detected.", + "workspace.status.dirty": "Unmerged changes detected in this workspace.", + "workspace.delete.title": "Delete workspace", + "workspace.delete.confirm": 'Delete workspace "{{name}}"?', + "workspace.delete.button": "Delete workspace", + "workspace.reset.title": "Reset workspace", + "workspace.reset.confirm": 'Reset workspace "{{name}}"?', + "workspace.reset.button": "Reset workspace", + "workspace.reset.archived.none": "No active sessions will be archived.", + "workspace.reset.archived.one": "1 session will be archived.", + "workspace.reset.archived.many": "{{count}} sessions will be archived.", + "workspace.reset.note": "This will reset the workspace to match the default branch.", +} diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts new file mode 100644 index 00000000000..8de149d2f5a --- /dev/null +++ b/packages/app/src/i18n/es.ts @@ -0,0 +1,583 @@ +export const dict = { + "command.category.suggested": "Sugerido", + "command.category.view": "Ver", + "command.category.project": "Proyecto", + "command.category.provider": "Proveedor", + "command.category.server": "Servidor", + "command.category.session": "Sesión", + "command.category.theme": "Tema", + "command.category.language": "Idioma", + "command.category.file": "Archivo", + "command.category.terminal": "Terminal", + "command.category.model": "Modelo", + "command.category.mcp": "MCP", + "command.category.agent": "Agente", + "command.category.permissions": "Permisos", + "command.category.workspace": "Espacio de trabajo", + + "theme.scheme.system": "Sistema", + "theme.scheme.light": "Claro", + "theme.scheme.dark": "Oscuro", + + "command.sidebar.toggle": "Alternar barra lateral", + "command.project.open": "Abrir proyecto", + "command.provider.connect": "Conectar proveedor", + "command.server.switch": "Cambiar servidor", + "command.session.previous": "Sesión anterior", + "command.session.next": "Siguiente sesión", + "command.session.archive": "Archivar sesión", + + "command.palette": "Paleta de comandos", + + "command.theme.cycle": "Alternar tema", + "command.theme.set": "Usar tema: {{theme}}", + "command.theme.scheme.cycle": "Alternar esquema de color", + "command.theme.scheme.set": "Usar esquema de color: {{scheme}}", + + "command.language.cycle": "Alternar idioma", + "command.language.set": "Usar idioma: {{language}}", + + "command.session.new": "Nueva sesión", + "command.file.open": "Abrir archivo", + "command.file.open.description": "Buscar archivos y comandos", + "command.terminal.toggle": "Alternar terminal", + "command.review.toggle": "Alternar revisión", + "command.terminal.new": "Nueva terminal", + "command.terminal.new.description": "Crear una nueva pestaña de terminal", + "command.steps.toggle": "Alternar pasos", + "command.steps.toggle.description": "Mostrar u ocultar pasos para el mensaje actual", + "command.message.previous": "Mensaje anterior", + "command.message.previous.description": "Ir al mensaje de usuario anterior", + "command.message.next": "Siguiente mensaje", + "command.message.next.description": "Ir al siguiente mensaje de usuario", + "command.model.choose": "Elegir modelo", + "command.model.choose.description": "Seleccionar un modelo diferente", + "command.mcp.toggle": "Alternar MCPs", + "command.mcp.toggle.description": "Alternar MCPs", + "command.agent.cycle": "Alternar agente", + "command.agent.cycle.description": "Cambiar al siguiente agente", + "command.agent.cycle.reverse": "Alternar agente hacia atrás", + "command.agent.cycle.reverse.description": "Cambiar al agente anterior", + "command.model.variant.cycle": "Alternar esfuerzo de pensamiento", + "command.model.variant.cycle.description": "Cambiar al siguiente nivel de esfuerzo", + "command.permissions.autoaccept.enable": "Aceptar ediciones automáticamente", + "command.permissions.autoaccept.disable": "Dejar de aceptar ediciones automáticamente", + "command.session.undo": "Deshacer", + "command.session.undo.description": "Deshacer el último mensaje", + "command.session.redo": "Rehacer", + "command.session.redo.description": "Rehacer el último mensaje deshecho", + "command.session.compact": "Compactar sesión", + "command.session.compact.description": "Resumir la sesión para reducir el tamaño del contexto", + "command.session.fork": "Bifurcar desde mensaje", + "command.session.fork.description": "Crear una nueva sesión desde un mensaje anterior", + "command.session.share": "Compartir sesión", + "command.session.share.description": "Compartir esta sesión y copiar la URL al portapapeles", + "command.session.unshare": "Dejar de compartir sesión", + "command.session.unshare.description": "Dejar de compartir esta sesión", + + "palette.search.placeholder": "Buscar archivos y comandos", + "palette.empty": "No se encontraron resultados", + "palette.group.commands": "Comandos", + "palette.group.files": "Archivos", + + "dialog.provider.search.placeholder": "Buscar proveedores", + "dialog.provider.empty": "No se encontraron proveedores", + "dialog.provider.group.popular": "Popular", + "dialog.provider.group.other": "Otro", + "dialog.provider.tag.recommended": "Recomendado", + "dialog.provider.anthropic.note": "Conectar con Claude Pro/Max o clave API", + + "dialog.model.select.title": "Seleccionar modelo", + "dialog.model.search.placeholder": "Buscar modelos", + "dialog.model.empty": "Sin resultados de modelos", + "dialog.model.manage": "Gestionar modelos", + "dialog.model.manage.description": "Personalizar qué modelos aparecen en el selector de modelos.", + + "dialog.model.unpaid.freeModels.title": "Modelos gratuitos proporcionados por OpenCode", + "dialog.model.unpaid.addMore.title": "Añadir más modelos de proveedores populares", + + "dialog.provider.viewAll": "Ver todos los proveedores", + + "provider.connect.title": "Conectar {{provider}}", + "provider.connect.title.anthropicProMax": "Iniciar sesión con Claude Pro/Max", + "provider.connect.selectMethod": "Seleccionar método de inicio de sesión para {{provider}}.", + "provider.connect.method.apiKey": "Clave API", + "provider.connect.status.inProgress": "Autorización en progreso...", + "provider.connect.status.waiting": "Esperando autorización...", + "provider.connect.status.failed": "Autorización fallida: {{error}}", + "provider.connect.apiKey.description": + "Introduce tu clave API de {{provider}} para conectar tu cuenta y usar modelos de {{provider}} en OpenCode.", + "provider.connect.apiKey.label": "Clave API de {{provider}}", + "provider.connect.apiKey.placeholder": "Clave API", + "provider.connect.apiKey.required": "La clave API es obligatoria", + "provider.connect.opencodeZen.line1": + "OpenCode Zen te da acceso a un conjunto curado de modelos fiables optimizados para agentes de programación.", + "provider.connect.opencodeZen.line2": + "Con una sola clave API obtendrás acceso a modelos como Claude, GPT, Gemini, GLM y más.", + "provider.connect.opencodeZen.visit.prefix": "Visita ", + "provider.connect.opencodeZen.visit.suffix": " para obtener tu clave API.", + "provider.connect.oauth.code.visit.prefix": "Visita ", + "provider.connect.oauth.code.visit.link": "este enlace", + "provider.connect.oauth.code.visit.suffix": + " para obtener tu código de autorización para conectar tu cuenta y usar modelos de {{provider}} en OpenCode.", + "provider.connect.oauth.code.label": "Código de autorización {{method}}", + "provider.connect.oauth.code.placeholder": "Código de autorización", + "provider.connect.oauth.code.required": "El código de autorización es obligatorio", + "provider.connect.oauth.code.invalid": "Código de autorización inválido", + "provider.connect.oauth.auto.visit.prefix": "Visita ", + "provider.connect.oauth.auto.visit.link": "este enlace", + "provider.connect.oauth.auto.visit.suffix": + " e introduce el código a continuación para conectar tu cuenta y usar modelos de {{provider}} en OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Código de confirmación", + "provider.connect.toast.connected.title": "{{provider}} conectado", + "provider.connect.toast.connected.description": "Los modelos de {{provider}} ahora están disponibles para usar.", + + "model.tag.free": "Gratis", + "model.tag.latest": "Último", + + "common.search.placeholder": "Buscar", + "common.goBack": "Volver", + "common.loading": "Cargando", + "common.cancel": "Cancelar", + "common.submit": "Enviar", + "common.save": "Guardar", + "common.saving": "Guardando...", + "common.default": "Predeterminado", + "common.attachment": "adjunto", + + "prompt.placeholder.shell": "Introduce comando de shell...", + "prompt.placeholder.normal": 'Pregunta cualquier cosa... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc para salir", + + "prompt.example.1": "Arreglar un TODO en el código", + "prompt.example.2": "¿Cuál es el stack tecnológico de este proyecto?", + "prompt.example.3": "Arreglar pruebas rotas", + "prompt.example.4": "Explicar cómo funciona la autenticación", + "prompt.example.5": "Encontrar y arreglar vulnerabilidades de seguridad", + "prompt.example.6": "Añadir pruebas unitarias para el servicio de usuario", + "prompt.example.7": "Refactorizar esta función para que sea más legible", + "prompt.example.8": "¿Qué significa este error?", + "prompt.example.9": "Ayúdame a depurar este problema", + "prompt.example.10": "Generar documentación de API", + "prompt.example.11": "Optimizar consultas a la base de datos", + "prompt.example.12": "Añadir validación de entrada", + "prompt.example.13": "Crear un nuevo componente para...", + "prompt.example.14": "¿Cómo despliego este proyecto?", + "prompt.example.15": "Revisar mi código para mejores prácticas", + "prompt.example.16": "Añadir manejo de errores a esta función", + "prompt.example.17": "Explicar este patrón de regex", + "prompt.example.18": "Convertir esto a TypeScript", + "prompt.example.19": "Añadir logging en todo el código", + "prompt.example.20": "¿Qué dependencias están desactualizadas?", + "prompt.example.21": "Ayúdame a escribir un script de migración", + "prompt.example.22": "Implementar caché para este endpoint", + "prompt.example.23": "Añadir paginación a esta lista", + "prompt.example.24": "Crear un comando CLI para...", + "prompt.example.25": "¿Cómo funcionan las variables de entorno aquí?", + + "prompt.popover.emptyResults": "Sin resultados coincidentes", + "prompt.popover.emptyCommands": "Sin comandos coincidentes", + "prompt.dropzone.label": "Suelta imágenes o PDFs aquí", + "prompt.slash.badge.custom": "personalizado", + "prompt.context.active": "activo", + "prompt.context.includeActiveFile": "Incluir archivo activo", + "prompt.context.removeActiveFile": "Eliminar archivo activo del contexto", + "prompt.context.removeFile": "Eliminar archivo del contexto", + "prompt.action.attachFile": "Adjuntar archivo", + "prompt.attachment.remove": "Eliminar adjunto", + "prompt.action.send": "Enviar", + "prompt.action.stop": "Detener", + + "prompt.toast.pasteUnsupported.title": "Pegado no soportado", + "prompt.toast.pasteUnsupported.description": "Solo se pueden pegar imágenes o PDFs aquí.", + "prompt.toast.modelAgentRequired.title": "Selecciona un agente y modelo", + "prompt.toast.modelAgentRequired.description": "Elige un agente y modelo antes de enviar un prompt.", + "prompt.toast.worktreeCreateFailed.title": "Fallo al crear el árbol de trabajo", + "prompt.toast.sessionCreateFailed.title": "Fallo al crear la sesión", + "prompt.toast.shellSendFailed.title": "Fallo al enviar comando de shell", + "prompt.toast.commandSendFailed.title": "Fallo al enviar comando", + "prompt.toast.promptSendFailed.title": "Fallo al enviar prompt", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} de {{total}} habilitados", + "dialog.mcp.empty": "No hay MCPs configurados", + + "mcp.status.connected": "conectado", + "mcp.status.failed": "fallido", + "mcp.status.needs_auth": "necesita auth", + "mcp.status.disabled": "deshabilitado", + + "dialog.fork.empty": "No hay mensajes desde donde bifurcar", + + "dialog.directory.search.placeholder": "Buscar carpetas", + "dialog.directory.empty": "No se encontraron carpetas", + + "dialog.server.title": "Servidores", + "dialog.server.description": "Cambiar a qué servidor de OpenCode se conecta esta app.", + "dialog.server.search.placeholder": "Buscar servidores", + "dialog.server.empty": "No hay servidores aún", + "dialog.server.add.title": "Añadir un servidor", + "dialog.server.add.url": "URL del servidor", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "No se pudo conectar al servidor", + "dialog.server.add.checking": "Comprobando...", + "dialog.server.add.button": "Añadir", + "dialog.server.default.title": "Servidor predeterminado", + "dialog.server.default.description": + "Conectar a este servidor al iniciar la app en lugar de iniciar un servidor local. Requiere reinicio.", + "dialog.server.default.none": "Ningún servidor seleccionado", + "dialog.server.default.set": "Establecer servidor actual como predeterminado", + "dialog.server.default.clear": "Limpiar", + "dialog.server.action.remove": "Eliminar servidor", + + "dialog.project.edit.title": "Editar proyecto", + "dialog.project.edit.name": "Nombre", + "dialog.project.edit.icon": "Icono", + "dialog.project.edit.icon.alt": "Icono del proyecto", + "dialog.project.edit.icon.hint": "Haz clic o arrastra una imagen", + "dialog.project.edit.icon.recommended": "Recomendado: 128x128px", + "dialog.project.edit.color": "Color", + "dialog.project.edit.color.select": "Seleccionar color {{color}}", + + "context.breakdown.title": "Desglose de Contexto", + "context.breakdown.note": + 'Desglose aproximado de tokens de entrada. "Otro" incluye definiciones de herramientas y sobrecarga.', + "context.breakdown.system": "Sistema", + "context.breakdown.user": "Usuario", + "context.breakdown.assistant": "Asistente", + "context.breakdown.tool": "Llamadas a herramientas", + "context.breakdown.other": "Otro", + + "context.systemPrompt.title": "Prompt del Sistema", + "context.rawMessages.title": "Mensajes en bruto", + + "context.stats.session": "Sesión", + "context.stats.messages": "Mensajes", + "context.stats.provider": "Proveedor", + "context.stats.model": "Modelo", + "context.stats.limit": "Límite de Contexto", + "context.stats.totalTokens": "Tokens Totales", + "context.stats.usage": "Uso", + "context.stats.inputTokens": "Tokens de Entrada", + "context.stats.outputTokens": "Tokens de Salida", + "context.stats.reasoningTokens": "Tokens de Razonamiento", + "context.stats.cacheTokens": "Tokens de Caché (lectura/escritura)", + "context.stats.userMessages": "Mensajes de Usuario", + "context.stats.assistantMessages": "Mensajes de Asistente", + "context.stats.totalCost": "Costo Total", + "context.stats.sessionCreated": "Sesión Creada", + "context.stats.lastActivity": "Última Actividad", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Uso", + "context.usage.cost": "Costo", + "context.usage.clickToView": "Haz clic para ver contexto", + "context.usage.view": "Ver uso del contexto", + + "language.en": "Inglés", + "language.zh": "Chino (simplificado)", + "language.zht": "Chino (tradicional)", + "language.ko": "Coreano", + "language.de": "Alemán", + "language.es": "Español", + "language.fr": "Francés", + "language.ja": "Japonés", + "language.da": "Danés", + "language.ru": "Ruso", + "language.pl": "Polaco", + "language.ar": "Árabe", + "language.no": "Noruego", + "language.br": "Portugués (Brasil)", + + "toast.language.title": "Idioma", + "toast.language.description": "Cambiado a {{language}}", + + "toast.theme.title": "Tema cambiado", + "toast.scheme.title": "Esquema de color", + + "toast.permissions.autoaccept.on.title": "Aceptando ediciones automáticamente", + "toast.permissions.autoaccept.on.description": "Los permisos de edición y escritura serán aprobados automáticamente", + "toast.permissions.autoaccept.off.title": "Se dejó de aceptar ediciones automáticamente", + "toast.permissions.autoaccept.off.description": "Los permisos de edición y escritura requerirán aprobación", + + "toast.model.none.title": "Ningún modelo seleccionado", + "toast.model.none.description": "Conecta un proveedor para resumir esta sesión", + + "toast.file.loadFailed.title": "Fallo al cargar archivo", + + "toast.session.share.copyFailed.title": "Fallo al copiar URL al portapapeles", + "toast.session.share.success.title": "Sesión compartida", + "toast.session.share.success.description": "¡URL compartida copiada al portapapeles!", + "toast.session.share.failed.title": "Fallo al compartir sesión", + "toast.session.share.failed.description": "Ocurrió un error al compartir la sesión", + + "toast.session.unshare.success.title": "Sesión dejó de compartirse", + "toast.session.unshare.success.description": "¡La sesión dejó de compartirse exitosamente!", + "toast.session.unshare.failed.title": "Fallo al dejar de compartir sesión", + "toast.session.unshare.failed.description": "Ocurrió un error al dejar de compartir la sesión", + + "toast.session.listFailed.title": "Fallo al cargar sesiones para {{project}}", + + "toast.update.title": "Actualización disponible", + "toast.update.description": "Una nueva versión de OpenCode ({{version}}) está disponible para instalar.", + "toast.update.action.installRestart": "Instalar y reiniciar", + "toast.update.action.notYet": "Todavía no", + + "error.page.title": "Algo salió mal", + "error.page.description": "Ocurrió un error al cargar la aplicación.", + "error.page.details.label": "Detalles del error", + "error.page.action.restart": "Reiniciar", + "error.page.action.checking": "Comprobando...", + "error.page.action.checkUpdates": "Buscar actualizaciones", + "error.page.action.updateTo": "Actualizar a {{version}}", + "error.page.report.prefix": "Por favor reporta este error al equipo de OpenCode", + "error.page.report.discord": "en Discord", + "error.page.version": "Versión: {{version}}", + + "error.dev.rootNotFound": + "Elemento raíz no encontrado. ¿Olvidaste añadirlo a tu index.html? ¿O tal vez el atributo id está mal escrito?", + + "error.globalSync.connectFailed": "No se pudo conectar al servidor. ¿Hay un servidor ejecutándose en `{{url}}`?", + + "error.chain.unknown": "Error desconocido", + "error.chain.causedBy": "Causado por:", + "error.chain.apiError": "Error de API", + "error.chain.status": "Estado: {{status}}", + "error.chain.retryable": "Reintentable: {{retryable}}", + "error.chain.responseBody": "Cuerpo de la respuesta:\n{{body}}", + "error.chain.didYouMean": "¿Quisiste decir: {{suggestions}}", + "error.chain.modelNotFound": "Modelo no encontrado: {{provider}}/{{model}}", + "error.chain.checkConfig": "Comprueba los nombres de proveedor/modelo en tu configuración (opencode.json)", + "error.chain.mcpFailed": 'El servidor MCP "{{name}}" falló. Nota, OpenCode no soporta autenticación MCP todavía.', + "error.chain.providerAuthFailed": "Autenticación de proveedor fallida ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Fallo al inicializar proveedor "{{provider}}". Comprueba credenciales y configuración.', + "error.chain.configJsonInvalid": "El archivo de configuración en {{path}} no es un JSON(C) válido", + "error.chain.configJsonInvalidWithMessage": + "El archivo de configuración en {{path}} no es un JSON(C) válido: {{message}}", + "error.chain.configDirectoryTypo": + 'El directorio "{{dir}}" en {{path}} no es válido. Renombra el directorio a "{{suggestion}}" o elimínalo. Esto es un error tipográfico común.', + "error.chain.configFrontmatterError": "Fallo al analizar frontmatter en {{path}}:\n{{message}}", + "error.chain.configInvalid": "El archivo de configuración en {{path}} es inválido", + "error.chain.configInvalidWithMessage": "El archivo de configuración en {{path}} es inválido: {{message}}", + + "notification.permission.title": "Permiso requerido", + "notification.permission.description": "{{sessionTitle}} en {{projectName}} necesita permiso", + "notification.question.title": "Pregunta", + "notification.question.description": "{{sessionTitle}} en {{projectName}} tiene una pregunta", + "notification.action.goToSession": "Ir a sesión", + + "notification.session.responseReady.title": "Respuesta lista", + "notification.session.error.title": "Error de sesión", + "notification.session.error.fallbackDescription": "Ocurrió un error", + + "home.recentProjects": "Proyectos recientes", + "home.empty.title": "Sin proyectos recientes", + "home.empty.description": "Empieza abriendo un proyecto local", + + "session.tab.session": "Sesión", + "session.tab.review": "Revisión", + "session.tab.context": "Contexto", + "session.panel.reviewAndFiles": "Revisión y archivos", + "session.review.filesChanged": "{{count}} Archivos Cambiados", + "session.review.loadingChanges": "Cargando cambios...", + "session.review.empty": "No hay cambios en esta sesión aún", + "session.messages.renderEarlier": "Renderizar mensajes anteriores", + "session.messages.loadingEarlier": "Cargando mensajes anteriores...", + "session.messages.loadEarlier": "Cargar mensajes anteriores", + "session.messages.loading": "Cargando mensajes...", + + "session.context.addToContext": "Añadir {{selection}} al contexto", + + "session.new.worktree.main": "Rama principal", + "session.new.worktree.mainWithBranch": "Rama principal ({{branch}})", + "session.new.worktree.create": "Crear nuevo árbol de trabajo", + "session.new.lastModified": "Última modificación", + + "session.header.search.placeholder": "Buscar {{project}}", + "session.header.searchFiles": "Buscar archivos", + + "session.share.popover.title": "Publicar en web", + "session.share.popover.description.shared": + "Esta sesión es pública en la web. Es accesible para cualquiera con el enlace.", + "session.share.popover.description.unshared": + "Compartir sesión públicamente en la web. Será accesible para cualquiera con el enlace.", + "session.share.action.share": "Compartir", + "session.share.action.publish": "Publicar", + "session.share.action.publishing": "Publicando...", + "session.share.action.unpublish": "Despublicar", + "session.share.action.unpublishing": "Despublicando...", + "session.share.action.view": "Ver", + "session.share.copy.copied": "Copiado", + "session.share.copy.copyLink": "Copiar enlace", + + "lsp.tooltip.none": "Sin servidores LSP", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Cargando prompt...", + "terminal.loading": "Cargando terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Cerrar terminal", + + "common.closeTab": "Cerrar pestaña", + "common.dismiss": "Descartar", + "common.requestFailed": "Solicitud fallida", + "common.moreOptions": "Más opciones", + "common.learnMore": "Saber más", + "common.rename": "Renombrar", + "common.reset": "Restablecer", + "common.archive": "Archivar", + "common.delete": "Eliminar", + "common.close": "Cerrar", + "common.edit": "Editar", + "common.loadMore": "Cargar más", + + "sidebar.nav.projectsAndSessions": "Proyectos y sesiones", + "sidebar.settings": "Ajustes", + "sidebar.help": "Ayuda", + "sidebar.workspaces.enable": "Habilitar espacios de trabajo", + "sidebar.workspaces.disable": "Deshabilitar espacios de trabajo", + "sidebar.gettingStarted.title": "Empezando", + "sidebar.gettingStarted.line1": "OpenCode incluye modelos gratuitos para que puedas empezar inmediatamente.", + "sidebar.gettingStarted.line2": "Conecta cualquier proveedor para usar modelos, inc. Claude, GPT, Gemini etc.", + "sidebar.project.recentSessions": "Sesiones recientes", + "sidebar.project.viewAllSessions": "Ver todas las sesiones", + + "settings.section.desktop": "Escritorio", + "settings.tab.general": "General", + "settings.tab.shortcuts": "Atajos", + + "settings.general.section.appearance": "Apariencia", + "settings.general.section.notifications": "Notificaciones del sistema", + "settings.general.section.sounds": "Efectos de sonido", + + "settings.general.row.language.title": "Idioma", + "settings.general.row.language.description": "Cambiar el idioma de visualización para OpenCode", + "settings.general.row.appearance.title": "Apariencia", + "settings.general.row.appearance.description": "Personaliza cómo se ve OpenCode en tu dispositivo", + "settings.general.row.theme.title": "Tema", + "settings.general.row.theme.description": "Personaliza el tema de OpenCode.", + "settings.general.row.font.title": "Fuente", + "settings.general.row.font.description": "Personaliza la fuente mono usada en bloques de código", + + "settings.general.notifications.agent.title": "Agente", + "settings.general.notifications.agent.description": + "Mostrar notificación del sistema cuando el agente termine o necesite atención", + "settings.general.notifications.permissions.title": "Permisos", + "settings.general.notifications.permissions.description": + "Mostrar notificación del sistema cuando se requiera un permiso", + "settings.general.notifications.errors.title": "Errores", + "settings.general.notifications.errors.description": "Mostrar notificación del sistema cuando ocurra un error", + + "settings.general.sounds.agent.title": "Agente", + "settings.general.sounds.agent.description": "Reproducir sonido cuando el agente termine o necesite atención", + "settings.general.sounds.permissions.title": "Permisos", + "settings.general.sounds.permissions.description": "Reproducir sonido cuando se requiera un permiso", + "settings.general.sounds.errors.title": "Errores", + "settings.general.sounds.errors.description": "Reproducir sonido cuando ocurra un error", + + "settings.shortcuts.title": "Atajos de teclado", + "settings.shortcuts.reset.button": "Restablecer a valores predeterminados", + "settings.shortcuts.reset.toast.title": "Atajos restablecidos", + "settings.shortcuts.reset.toast.description": + "Los atajos de teclado han sido restablecidos a los valores predeterminados.", + "settings.shortcuts.conflict.title": "Atajo ya en uso", + "settings.shortcuts.conflict.description": "{{keybind}} ya está asignado a {{titles}}.", + "settings.shortcuts.unassigned": "Sin asignar", + "settings.shortcuts.pressKeys": "Presiona teclas", + "settings.shortcuts.search.placeholder": "Buscar atajos", + "settings.shortcuts.search.empty": "No se encontraron atajos", + + "settings.shortcuts.group.general": "General", + "settings.shortcuts.group.session": "Sesión", + "settings.shortcuts.group.navigation": "Navegación", + "settings.shortcuts.group.modelAndAgent": "Modelo y agente", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Proveedores", + "settings.providers.description": "La configuración de proveedores estará disponible aquí.", + "settings.models.title": "Modelos", + "settings.models.description": "La configuración de modelos estará disponible aquí.", + "settings.agents.title": "Agentes", + "settings.agents.description": "La configuración de agentes estará disponible aquí.", + "settings.commands.title": "Comandos", + "settings.commands.description": "La configuración de comandos estará disponible aquí.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "La configuración de MCP estará disponible aquí.", + + "settings.permissions.title": "Permisos", + "settings.permissions.description": "Controla qué herramientas puede usar el servidor por defecto.", + "settings.permissions.section.tools": "Herramientas", + "settings.permissions.toast.updateFailed.title": "Fallo al actualizar permisos", + + "settings.permissions.action.allow": "Permitir", + "settings.permissions.action.ask": "Preguntar", + "settings.permissions.action.deny": "Denegar", + + "settings.permissions.tool.read.title": "Leer", + "settings.permissions.tool.read.description": "Leer un archivo (coincide con la ruta del archivo)", + "settings.permissions.tool.edit.title": "Editar", + "settings.permissions.tool.edit.description": + "Modificar archivos, incluyendo ediciones, escrituras, parches y multi-ediciones", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Coincidir archivos usando patrones glob", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Buscar contenidos de archivo usando expresiones regulares", + "settings.permissions.tool.list.title": "Listar", + "settings.permissions.tool.list.description": "Listar archivos dentro de un directorio", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Ejecutar comandos de shell", + "settings.permissions.tool.task.title": "Tarea", + "settings.permissions.tool.task.description": "Lanzar sub-agentes", + "settings.permissions.tool.skill.title": "Habilidad", + "settings.permissions.tool.skill.description": "Cargar una habilidad por nombre", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Ejecutar consultas de servidor de lenguaje", + "settings.permissions.tool.todoread.title": "Leer Todo", + "settings.permissions.tool.todoread.description": "Leer la lista de tareas", + "settings.permissions.tool.todowrite.title": "Escribir Todo", + "settings.permissions.tool.todowrite.description": "Actualizar la lista de tareas", + "settings.permissions.tool.webfetch.title": "Web Fetch", + "settings.permissions.tool.webfetch.description": "Obtener contenido de una URL", + "settings.permissions.tool.websearch.title": "Búsqueda Web", + "settings.permissions.tool.websearch.description": "Buscar en la web", + "settings.permissions.tool.codesearch.title": "Búsqueda de Código", + "settings.permissions.tool.codesearch.description": "Buscar código en la web", + "settings.permissions.tool.external_directory.title": "Directorio Externo", + "settings.permissions.tool.external_directory.description": "Acceder a archivos fuera del directorio del proyecto", + "settings.permissions.tool.doom_loop.title": "Bucle Infinito", + "settings.permissions.tool.doom_loop.description": "Detectar llamadas a herramientas repetidas con entrada idéntica", + + "session.delete.failed.title": "Fallo al eliminar sesión", + "session.delete.title": "Eliminar sesión", + "session.delete.confirm": '¿Eliminar sesión "{{name}}"?', + "session.delete.button": "Eliminar sesión", + + "workspace.new": "Nuevo espacio de trabajo", + "workspace.type.local": "local", + "workspace.type.sandbox": "sandbox", + "workspace.create.failed.title": "Fallo al crear espacio de trabajo", + "workspace.delete.failed.title": "Fallo al eliminar espacio de trabajo", + "workspace.resetting.title": "Restableciendo espacio de trabajo", + "workspace.resetting.description": "Esto puede tomar un minuto.", + "workspace.reset.failed.title": "Fallo al restablecer espacio de trabajo", + "workspace.reset.success.title": "Espacio de trabajo restablecido", + "workspace.reset.success.description": "El espacio de trabajo ahora coincide con la rama predeterminada.", + "workspace.status.checking": "Comprobando cambios no fusionados...", + "workspace.status.error": "No se pudo verificar el estado de git.", + "workspace.status.clean": "No se detectaron cambios no fusionados.", + "workspace.status.dirty": "Cambios no fusionados detectados en este espacio de trabajo.", + "workspace.delete.title": "Eliminar espacio de trabajo", + "workspace.delete.confirm": '¿Eliminar espacio de trabajo "{{name}}"?', + "workspace.delete.button": "Eliminar espacio de trabajo", + "workspace.reset.title": "Restablecer espacio de trabajo", + "workspace.reset.confirm": '¿Restablecer espacio de trabajo "{{name}}"?', + "workspace.reset.button": "Restablecer espacio de trabajo", + "workspace.reset.archived.none": "No se archivarán sesiones activas.", + "workspace.reset.archived.one": "1 sesión será archivada.", + "workspace.reset.archived.many": "{{count}} sesiones serán archivadas.", + "workspace.reset.note": "Esto restablecerá el espacio de trabajo para coincidir con la rama predeterminada.", +} diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts new file mode 100644 index 00000000000..8ac4d5dd402 --- /dev/null +++ b/packages/app/src/i18n/fr.ts @@ -0,0 +1,590 @@ +export const dict = { + "command.category.suggested": "Suggéré", + "command.category.view": "Affichage", + "command.category.project": "Projet", + "command.category.provider": "Fournisseur", + "command.category.server": "Serveur", + "command.category.session": "Session", + "command.category.theme": "Thème", + "command.category.language": "Langue", + "command.category.file": "Fichier", + "command.category.terminal": "Terminal", + "command.category.model": "Modèle", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Permissions", + "command.category.workspace": "Espace de travail", + + "theme.scheme.system": "Système", + "theme.scheme.light": "Clair", + "theme.scheme.dark": "Sombre", + + "command.sidebar.toggle": "Basculer la barre latérale", + "command.project.open": "Ouvrir un projet", + "command.provider.connect": "Connecter un fournisseur", + "command.server.switch": "Changer de serveur", + "command.session.previous": "Session précédente", + "command.session.next": "Session suivante", + "command.session.archive": "Archiver la session", + + "command.palette": "Palette de commandes", + + "command.theme.cycle": "Changer de thème", + "command.theme.set": "Utiliser le thème : {{theme}}", + "command.theme.scheme.cycle": "Changer de schéma de couleurs", + "command.theme.scheme.set": "Utiliser le schéma de couleurs : {{scheme}}", + + "command.language.cycle": "Changer de langue", + "command.language.set": "Utiliser la langue : {{language}}", + + "command.session.new": "Nouvelle session", + "command.file.open": "Ouvrir un fichier", + "command.file.open.description": "Rechercher des fichiers et des commandes", + "command.terminal.toggle": "Basculer le terminal", + "command.review.toggle": "Basculer la revue", + "command.terminal.new": "Nouveau terminal", + "command.terminal.new.description": "Créer un nouvel onglet de terminal", + "command.steps.toggle": "Basculer les étapes", + "command.steps.toggle.description": "Afficher ou masquer les étapes du message actuel", + "command.message.previous": "Message précédent", + "command.message.previous.description": "Aller au message utilisateur précédent", + "command.message.next": "Message suivant", + "command.message.next.description": "Aller au message utilisateur suivant", + "command.model.choose": "Choisir le modèle", + "command.model.choose.description": "Sélectionner un modèle différent", + "command.mcp.toggle": "Basculer MCP", + "command.mcp.toggle.description": "Basculer les MCPs", + "command.agent.cycle": "Changer d'agent", + "command.agent.cycle.description": "Passer à l'agent suivant", + "command.agent.cycle.reverse": "Changer d'agent (inverse)", + "command.agent.cycle.reverse.description": "Passer à l'agent précédent", + "command.model.variant.cycle": "Changer l'effort de réflexion", + "command.model.variant.cycle.description": "Passer au niveau d'effort suivant", + "command.permissions.autoaccept.enable": "Accepter automatiquement les modifications", + "command.permissions.autoaccept.disable": "Arrêter l'acceptation automatique des modifications", + "command.session.undo": "Annuler", + "command.session.undo.description": "Annuler le dernier message", + "command.session.redo": "Rétablir", + "command.session.redo.description": "Rétablir le dernier message annulé", + "command.session.compact": "Compacter la session", + "command.session.compact.description": "Résumer la session pour réduire la taille du contexte", + "command.session.fork": "Bifurquer à partir du message", + "command.session.fork.description": "Créer une nouvelle session à partir d'un message précédent", + "command.session.share": "Partager la session", + "command.session.share.description": "Partager cette session et copier l'URL dans le presse-papiers", + "command.session.unshare": "Ne plus partager la session", + "command.session.unshare.description": "Arrêter de partager cette session", + + "palette.search.placeholder": "Rechercher des fichiers et des commandes", + "palette.empty": "Aucun résultat trouvé", + "palette.group.commands": "Commandes", + "palette.group.files": "Fichiers", + + "dialog.provider.search.placeholder": "Rechercher des fournisseurs", + "dialog.provider.empty": "Aucun fournisseur trouvé", + "dialog.provider.group.popular": "Populaire", + "dialog.provider.group.other": "Autre", + "dialog.provider.tag.recommended": "Recommandé", + "dialog.provider.anthropic.note": "Connectez-vous avec Claude Pro/Max ou une clé API", + + "dialog.model.select.title": "Sélectionner un modèle", + "dialog.model.search.placeholder": "Rechercher des modèles", + "dialog.model.empty": "Aucun résultat de modèle", + "dialog.model.manage": "Gérer les modèles", + "dialog.model.manage.description": "Personnalisez les modèles qui apparaissent dans le sélecteur.", + + "dialog.model.unpaid.freeModels.title": "Modèles gratuits fournis par OpenCode", + "dialog.model.unpaid.addMore.title": "Ajouter plus de modèles de fournisseurs populaires", + + "dialog.provider.viewAll": "Voir tous les fournisseurs", + + "provider.connect.title": "Connecter {{provider}}", + "provider.connect.title.anthropicProMax": "Connexion avec Claude Pro/Max", + "provider.connect.selectMethod": "Sélectionnez la méthode de connexion pour {{provider}}.", + "provider.connect.method.apiKey": "Clé API", + "provider.connect.status.inProgress": "Autorisation en cours...", + "provider.connect.status.waiting": "En attente d'autorisation...", + "provider.connect.status.failed": "Échec de l'autorisation : {{error}}", + "provider.connect.apiKey.description": + "Entrez votre clé API {{provider}} pour connecter votre compte et utiliser les modèles {{provider}} dans OpenCode.", + "provider.connect.apiKey.label": "Clé API {{provider}}", + "provider.connect.apiKey.placeholder": "Clé API", + "provider.connect.apiKey.required": "La clé API est requise", + "provider.connect.opencodeZen.line1": + "OpenCode Zen vous donne accès à un ensemble sélectionné de modèles fiables et optimisés pour les agents de codage.", + "provider.connect.opencodeZen.line2": + "Avec une seule clé API, vous aurez accès à des modèles tels que Claude, GPT, Gemini, GLM et plus encore.", + "provider.connect.opencodeZen.visit.prefix": "Visitez ", + "provider.connect.opencodeZen.visit.suffix": " pour récupérer votre clé API.", + "provider.connect.oauth.code.visit.prefix": "Visitez ", + "provider.connect.oauth.code.visit.link": "ce lien", + "provider.connect.oauth.code.visit.suffix": + " pour récupérer votre code d'autorisation afin de connecter votre compte et utiliser les modèles {{provider}} dans OpenCode.", + "provider.connect.oauth.code.label": "Code d'autorisation {{method}}", + "provider.connect.oauth.code.placeholder": "Code d'autorisation", + "provider.connect.oauth.code.required": "Le code d'autorisation est requis", + "provider.connect.oauth.code.invalid": "Code d'autorisation invalide", + "provider.connect.oauth.auto.visit.prefix": "Visitez ", + "provider.connect.oauth.auto.visit.link": "ce lien", + "provider.connect.oauth.auto.visit.suffix": + " et entrez le code ci-dessous pour connecter votre compte et utiliser les modèles {{provider}} dans OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Code de confirmation", + "provider.connect.toast.connected.title": "{{provider}} connecté", + "provider.connect.toast.connected.description": "Les modèles {{provider}} sont maintenant disponibles.", + + "model.tag.free": "Gratuit", + "model.tag.latest": "Dernier", + + "common.search.placeholder": "Rechercher", + "common.goBack": "Retour", + "common.loading": "Chargement", + "common.cancel": "Annuler", + "common.submit": "Soumettre", + "common.save": "Enregistrer", + "common.saving": "Enregistrement...", + "common.default": "Défaut", + "common.attachment": "pièce jointe", + + "prompt.placeholder.shell": "Entrez une commande shell...", + "prompt.placeholder.normal": 'Demandez n\'importe quoi... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "esc pour quitter", + + "prompt.example.1": "Corriger un TODO dans la base de code", + "prompt.example.2": "Quelle est la pile technique de ce projet ?", + "prompt.example.3": "Réparer les tests échoués", + "prompt.example.4": "Expliquer comment fonctionne l'authentification", + "prompt.example.5": "Trouver et corriger les vulnérabilités de sécurité", + "prompt.example.6": "Ajouter des tests unitaires pour le service utilisateur", + "prompt.example.7": "Refactoriser cette fonction pour être plus lisible", + "prompt.example.8": "Que signifie cette erreur ?", + "prompt.example.9": "Aidez-moi à déboguer ce problème", + "prompt.example.10": "Générer la documentation de l'API", + "prompt.example.11": "Optimiser les requêtes de base de données", + "prompt.example.12": "Ajouter une validation d'entrée", + "prompt.example.13": "Créer un nouveau composant pour...", + "prompt.example.14": "Comment déployer ce projet ?", + "prompt.example.15": "Vérifier mon code pour les meilleures pratiques", + "prompt.example.16": "Ajouter la gestion des erreurs à cette fonction", + "prompt.example.17": "Expliquer ce modèle regex", + "prompt.example.18": "Convertir ceci en TypeScript", + "prompt.example.19": "Ajouter des logs dans toute la base de code", + "prompt.example.20": "Quelles dépendances sont obsolètes ?", + "prompt.example.21": "Aidez-moi à écrire un script de migration", + "prompt.example.22": "Implémenter la mise en cache pour ce point de terminaison", + "prompt.example.23": "Ajouter la pagination à cette liste", + "prompt.example.24": "Créer une commande CLI pour...", + "prompt.example.25": "Comment fonctionnent les variables d'environnement ici ?", + + "prompt.popover.emptyResults": "Aucun résultat correspondant", + "prompt.popover.emptyCommands": "Aucune commande correspondante", + "prompt.dropzone.label": "Déposez des images ou des PDF ici", + "prompt.slash.badge.custom": "personnalisé", + "prompt.context.active": "actif", + "prompt.context.includeActiveFile": "Inclure le fichier actif", + "prompt.context.removeActiveFile": "Retirer le fichier actif du contexte", + "prompt.context.removeFile": "Retirer le fichier du contexte", + "prompt.action.attachFile": "Joindre un fichier", + "prompt.attachment.remove": "Supprimer la pièce jointe", + "prompt.action.send": "Envoyer", + "prompt.action.stop": "Arrêter", + + "prompt.toast.pasteUnsupported.title": "Collage non supporté", + "prompt.toast.pasteUnsupported.description": "Seules les images ou les PDF peuvent être collés ici.", + "prompt.toast.modelAgentRequired.title": "Sélectionnez un agent et un modèle", + "prompt.toast.modelAgentRequired.description": "Choisissez un agent et un modèle avant d'envoyer un message.", + "prompt.toast.worktreeCreateFailed.title": "Échec de la création de l'arbre de travail", + "prompt.toast.sessionCreateFailed.title": "Échec de la création de la session", + "prompt.toast.shellSendFailed.title": "Échec de l'envoi de la commande shell", + "prompt.toast.commandSendFailed.title": "Échec de l'envoi de la commande", + "prompt.toast.promptSendFailed.title": "Échec de l'envoi du message", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} sur {{total}} activés", + "dialog.mcp.empty": "Aucun MCP configuré", + + "mcp.status.connected": "connecté", + "mcp.status.failed": "échoué", + "mcp.status.needs_auth": "nécessite auth", + "mcp.status.disabled": "désactivé", + + "dialog.fork.empty": "Aucun message à partir duquel bifurquer", + + "dialog.directory.search.placeholder": "Rechercher des dossiers", + "dialog.directory.empty": "Aucun dossier trouvé", + + "dialog.server.title": "Serveurs", + "dialog.server.description": "Changez le serveur OpenCode auquel cette application se connecte.", + "dialog.server.search.placeholder": "Rechercher des serveurs", + "dialog.server.empty": "Aucun serveur pour l'instant", + "dialog.server.add.title": "Ajouter un serveur", + "dialog.server.add.url": "URL du serveur", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Impossible de se connecter au serveur", + "dialog.server.add.checking": "Vérification...", + "dialog.server.add.button": "Ajouter", + "dialog.server.default.title": "Serveur par défaut", + "dialog.server.default.description": + "Se connecter à ce serveur au lancement de l'application au lieu de démarrer un serveur local. Nécessite un redémarrage.", + "dialog.server.default.none": "Aucun serveur sélectionné", + "dialog.server.default.set": "Définir le serveur actuel comme défaut", + "dialog.server.default.clear": "Effacer", + "dialog.server.action.remove": "Supprimer le serveur", + + "dialog.project.edit.title": "Modifier le projet", + "dialog.project.edit.name": "Nom", + "dialog.project.edit.icon": "Icône", + "dialog.project.edit.icon.alt": "Icône du projet", + "dialog.project.edit.icon.hint": "Cliquez ou faites glisser une image", + "dialog.project.edit.icon.recommended": "Recommandé : 128x128px", + "dialog.project.edit.color": "Couleur", + "dialog.project.edit.color.select": "Sélectionner la couleur {{color}}", + + "context.breakdown.title": "Répartition du contexte", + "context.breakdown.note": + "Répartition approximative des jetons d'entrée. \"Autre\" inclut les définitions d'outils et les frais généraux.", + "context.breakdown.system": "Système", + "context.breakdown.user": "Utilisateur", + "context.breakdown.assistant": "Assistant", + "context.breakdown.tool": "Appels d'outils", + "context.breakdown.other": "Autre", + + "context.systemPrompt.title": "Prompt système", + "context.rawMessages.title": "Messages bruts", + + "context.stats.session": "Session", + "context.stats.messages": "Messages", + "context.stats.provider": "Fournisseur", + "context.stats.model": "Modèle", + "context.stats.limit": "Limite de contexte", + "context.stats.totalTokens": "Total des jetons", + "context.stats.usage": "Utilisation", + "context.stats.inputTokens": "Jetons d'entrée", + "context.stats.outputTokens": "Jetons de sortie", + "context.stats.reasoningTokens": "Jetons de raisonnement", + "context.stats.cacheTokens": "Jetons de cache (lecture/écriture)", + "context.stats.userMessages": "Messages utilisateur", + "context.stats.assistantMessages": "Messages assistant", + "context.stats.totalCost": "Coût total", + "context.stats.sessionCreated": "Session créée", + "context.stats.lastActivity": "Dernière activité", + + "context.usage.tokens": "Jetons", + "context.usage.usage": "Utilisation", + "context.usage.cost": "Coût", + "context.usage.clickToView": "Cliquez pour voir le contexte", + "context.usage.view": "Voir l'utilisation du contexte", + + "language.en": "Anglais", + "language.zh": "Chinois (simplifié)", + "language.zht": "Chinois (traditionnel)", + "language.ko": "Coréen", + "language.de": "Allemand", + "language.es": "Espagnol", + "language.fr": "Français", + "language.ja": "Japonais", + "language.da": "Danois", + "language.ru": "Russe", + "language.pl": "Polonais", + "language.ar": "Arabe", + "language.no": "Norvégien", + "language.br": "Portugais (Brésil)", + + "toast.language.title": "Langue", + "toast.language.description": "Passé à {{language}}", + + "toast.theme.title": "Thème changé", + "toast.scheme.title": "Schéma de couleurs", + + "toast.permissions.autoaccept.on.title": "Acceptation auto des modifications", + "toast.permissions.autoaccept.on.description": + "Les permissions de modification et d'écriture seront automatiquement approuvées", + "toast.permissions.autoaccept.off.title": "Arrêt acceptation auto des modifications", + "toast.permissions.autoaccept.off.description": + "Les permissions de modification et d'écriture nécessiteront une approbation", + + "toast.model.none.title": "Aucun modèle sélectionné", + "toast.model.none.description": "Connectez un fournisseur pour résumer cette session", + + "toast.file.loadFailed.title": "Échec du chargement du fichier", + + "toast.session.share.copyFailed.title": "Échec de la copie de l'URL dans le presse-papiers", + "toast.session.share.success.title": "Session partagée", + "toast.session.share.success.description": "URL de partage copiée dans le presse-papiers !", + "toast.session.share.failed.title": "Échec du partage de la session", + "toast.session.share.failed.description": "Une erreur s'est produite lors du partage de la session", + + "toast.session.unshare.success.title": "Session non partagée", + "toast.session.unshare.success.description": "Session non partagée avec succès !", + "toast.session.unshare.failed.title": "Échec de l'annulation du partage", + "toast.session.unshare.failed.description": "Une erreur s'est produite lors de l'annulation du partage de la session", + + "toast.session.listFailed.title": "Échec du chargement des sessions pour {{project}}", + + "toast.update.title": "Mise à jour disponible", + "toast.update.description": + "Une nouvelle version d'OpenCode ({{version}}) est maintenant disponible pour installation.", + "toast.update.action.installRestart": "Installer et redémarrer", + "toast.update.action.notYet": "Pas encore", + + "error.page.title": "Quelque chose s'est mal passé", + "error.page.description": "Une erreur s'est produite lors du chargement de l'application.", + "error.page.details.label": "Détails de l'erreur", + "error.page.action.restart": "Redémarrer", + "error.page.action.checking": "Vérification...", + "error.page.action.checkUpdates": "Vérifier les mises à jour", + "error.page.action.updateTo": "Mettre à jour vers {{version}}", + "error.page.report.prefix": "Veuillez signaler cette erreur à l'équipe OpenCode", + "error.page.report.discord": "sur Discord", + "error.page.version": "Version : {{version}}", + + "error.dev.rootNotFound": + "Élément racine introuvable. Avez-vous oublié de l'ajouter à votre index.html ? Ou peut-être que l'attribut id est mal orthographié ?", + + "error.globalSync.connectFailed": + "Impossible de se connecter au serveur. Y a-t-il un serveur en cours d'exécution à `{{url}}` ?", + + "error.chain.unknown": "Erreur inconnue", + "error.chain.causedBy": "Causé par :", + "error.chain.apiError": "Erreur API", + "error.chain.status": "Statut : {{status}}", + "error.chain.retryable": "Réessayable : {{retryable}}", + "error.chain.responseBody": "Corps de la réponse :\n{{body}}", + "error.chain.didYouMean": "Vouliez-vous dire : {{suggestions}}", + "error.chain.modelNotFound": "Modèle introuvable : {{provider}}/{{model}}", + "error.chain.checkConfig": "Vérifiez votre configuration (opencode.json) pour les noms de fournisseur/modèle", + "error.chain.mcpFailed": + "Le serveur MCP \"{{name}}\" a échoué. Notez qu'OpenCode ne supporte pas encore l'authentification MCP.", + "error.chain.providerAuthFailed": "Échec de l'authentification du fournisseur ({{provider}}) : {{message}}", + "error.chain.providerInitFailed": + 'Échec de l\'initialisation du fournisseur "{{provider}}". Vérifiez les identifiants et la configuration.', + "error.chain.configJsonInvalid": "Le fichier de configuration à {{path}} n'est pas un JSON(C) valide", + "error.chain.configJsonInvalidWithMessage": + "Le fichier de configuration à {{path}} n'est pas un JSON(C) valide : {{message}}", + "error.chain.configDirectoryTypo": + 'Le répertoire "{{dir}}" dans {{path}} n\'est pas valide. Renommez le répertoire en "{{suggestion}}" ou supprimez-le. C\'est une faute de frappe courante.', + "error.chain.configFrontmatterError": "Échec de l'analyse du frontmatter dans {{path}} :\n{{message}}", + "error.chain.configInvalid": "Le fichier de configuration à {{path}} est invalide", + "error.chain.configInvalidWithMessage": "Le fichier de configuration à {{path}} est invalide : {{message}}", + + "notification.permission.title": "Permission requise", + "notification.permission.description": "{{sessionTitle}} dans {{projectName}} a besoin d'une permission", + "notification.question.title": "Question", + "notification.question.description": "{{sessionTitle}} dans {{projectName}} a une question", + "notification.action.goToSession": "Aller à la session", + + "notification.session.responseReady.title": "Réponse prête", + "notification.session.error.title": "Erreur de session", + "notification.session.error.fallbackDescription": "Une erreur s'est produite", + + "home.recentProjects": "Projets récents", + "home.empty.title": "Aucun projet récent", + "home.empty.description": "Commencez par ouvrir un projet local", + + "session.tab.session": "Session", + "session.tab.review": "Revue", + "session.tab.context": "Contexte", + "session.panel.reviewAndFiles": "Revue et fichiers", + "session.review.filesChanged": "{{count}} fichiers modifiés", + "session.review.loadingChanges": "Chargement des modifications...", + "session.review.empty": "Aucune modification dans cette session pour l'instant", + "session.messages.renderEarlier": "Afficher les messages précédents", + "session.messages.loadingEarlier": "Chargement des messages précédents...", + "session.messages.loadEarlier": "Charger les messages précédents", + "session.messages.loading": "Chargement des messages...", + + "session.context.addToContext": "Ajouter {{selection}} au contexte", + + "session.new.worktree.main": "Branche principale", + "session.new.worktree.mainWithBranch": "Branche principale ({{branch}})", + "session.new.worktree.create": "Créer un nouvel arbre de travail", + "session.new.lastModified": "Dernière modification", + + "session.header.search.placeholder": "Rechercher {{project}}", + "session.header.searchFiles": "Rechercher des fichiers", + + "session.share.popover.title": "Publier sur le web", + "session.share.popover.description.shared": + "Cette session est publique sur le web. Elle est accessible à toute personne disposant du lien.", + "session.share.popover.description.unshared": + "Partager la session publiquement sur le web. Elle sera accessible à toute personne disposant du lien.", + "session.share.action.share": "Partager", + "session.share.action.publish": "Publier", + "session.share.action.publishing": "Publication...", + "session.share.action.unpublish": "Dépublier", + "session.share.action.unpublishing": "Dépublication...", + "session.share.action.view": "Voir", + "session.share.copy.copied": "Copié", + "session.share.copy.copyLink": "Copier le lien", + + "lsp.tooltip.none": "Aucun serveur LSP", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Chargement du prompt...", + "terminal.loading": "Chargement du terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Fermer le terminal", + + "common.closeTab": "Fermer l'onglet", + "common.dismiss": "Ignorer", + "common.requestFailed": "La demande a échoué", + "common.moreOptions": "Plus d'options", + "common.learnMore": "En savoir plus", + "common.rename": "Renommer", + "common.reset": "Réinitialiser", + "common.archive": "Archiver", + "common.delete": "Supprimer", + "common.close": "Fermer", + "common.edit": "Modifier", + "common.loadMore": "Charger plus", + + "sidebar.nav.projectsAndSessions": "Projets et sessions", + "sidebar.settings": "Paramètres", + "sidebar.help": "Aide", + "sidebar.workspaces.enable": "Activer les espaces de travail", + "sidebar.workspaces.disable": "Désactiver les espaces de travail", + "sidebar.gettingStarted.title": "Commencer", + "sidebar.gettingStarted.line1": + "OpenCode inclut des modèles gratuits pour que vous puissiez commencer immédiatement.", + "sidebar.gettingStarted.line2": + "Connectez n'importe quel fournisseur pour utiliser des modèles, y compris Claude, GPT, Gemini etc.", + "sidebar.project.recentSessions": "Sessions récentes", + "sidebar.project.viewAllSessions": "Voir toutes les sessions", + + "settings.section.desktop": "Bureau", + "settings.tab.general": "Général", + "settings.tab.shortcuts": "Raccourcis", + + "settings.general.section.appearance": "Apparence", + "settings.general.section.notifications": "Notifications système", + "settings.general.section.sounds": "Effets sonores", + + "settings.general.row.language.title": "Langue", + "settings.general.row.language.description": "Changer la langue d'affichage pour OpenCode", + "settings.general.row.appearance.title": "Apparence", + "settings.general.row.appearance.description": "Personnaliser l'apparence d'OpenCode sur votre appareil", + "settings.general.row.theme.title": "Thème", + "settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.", + "settings.general.row.font.title": "Police", + "settings.general.row.font.description": "Personnaliser la police mono utilisée dans les blocs de code", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Afficher une notification système lorsque l'agent a terminé ou nécessite une attention", + "settings.general.notifications.permissions.title": "Permissions", + "settings.general.notifications.permissions.description": + "Afficher une notification système lorsqu'une permission est requise", + "settings.general.notifications.errors.title": "Erreurs", + "settings.general.notifications.errors.description": "Afficher une notification système lorsqu'une erreur se produit", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Jouer un son lorsque l'agent a terminé ou nécessite une attention", + "settings.general.sounds.permissions.title": "Permissions", + "settings.general.sounds.permissions.description": "Jouer un son lorsqu'une permission est requise", + "settings.general.sounds.errors.title": "Erreurs", + "settings.general.sounds.errors.description": "Jouer un son lorsqu'une erreur se produit", + + "settings.shortcuts.title": "Raccourcis clavier", + "settings.shortcuts.reset.button": "Rétablir les défauts", + "settings.shortcuts.reset.toast.title": "Raccourcis réinitialisés", + "settings.shortcuts.reset.toast.description": "Les raccourcis clavier ont été réinitialisés aux valeurs par défaut.", + "settings.shortcuts.conflict.title": "Raccourci déjà utilisé", + "settings.shortcuts.conflict.description": "{{keybind}} est déjà assigné à {{titles}}.", + "settings.shortcuts.unassigned": "Non assigné", + "settings.shortcuts.pressKeys": "Appuyez sur les touches", + "settings.shortcuts.search.placeholder": "Rechercher des raccourcis", + "settings.shortcuts.search.empty": "Aucun raccourci trouvé", + + "settings.shortcuts.group.general": "Général", + "settings.shortcuts.group.session": "Session", + "settings.shortcuts.group.navigation": "Navigation", + "settings.shortcuts.group.modelAndAgent": "Modèle et agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Fournisseurs", + "settings.providers.description": "Les paramètres des fournisseurs seront configurables ici.", + "settings.models.title": "Modèles", + "settings.models.description": "Les paramètres des modèles seront configurables ici.", + "settings.agents.title": "Agents", + "settings.agents.description": "Les paramètres des agents seront configurables ici.", + "settings.commands.title": "Commandes", + "settings.commands.description": "Les paramètres des commandes seront configurables ici.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "Les paramètres MCP seront configurables ici.", + + "settings.permissions.title": "Permissions", + "settings.permissions.description": "Contrôlez les outils que le serveur peut utiliser par défaut.", + "settings.permissions.section.tools": "Outils", + "settings.permissions.toast.updateFailed.title": "Échec de la mise à jour des permissions", + + "settings.permissions.action.allow": "Autoriser", + "settings.permissions.action.ask": "Demander", + "settings.permissions.action.deny": "Refuser", + + "settings.permissions.tool.read.title": "Lire", + "settings.permissions.tool.read.description": "Lecture d'un fichier (correspond au chemin du fichier)", + "settings.permissions.tool.edit.title": "Modifier", + "settings.permissions.tool.edit.description": + "Modifier des fichiers, y compris les modifications, écritures, patchs et multi-modifications", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Correspondre aux fichiers utilisant des modèles glob", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": + "Rechercher dans le contenu des fichiers à l'aide d'expressions régulières", + "settings.permissions.tool.list.title": "Lister", + "settings.permissions.tool.list.description": "Lister les fichiers dans un répertoire", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Exécuter des commandes shell", + "settings.permissions.tool.task.title": "Tâche", + "settings.permissions.tool.task.description": "Lancer des sous-agents", + "settings.permissions.tool.skill.title": "Compétence", + "settings.permissions.tool.skill.description": "Charger une compétence par son nom", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Exécuter des requêtes de serveur de langage", + "settings.permissions.tool.todoread.title": "Lire Todo", + "settings.permissions.tool.todoread.description": "Lire la liste de tâches", + "settings.permissions.tool.todowrite.title": "Écrire Todo", + "settings.permissions.tool.todowrite.description": "Mettre à jour la liste de tâches", + "settings.permissions.tool.webfetch.title": "Récupération Web", + "settings.permissions.tool.webfetch.description": "Récupérer le contenu d'une URL", + "settings.permissions.tool.websearch.title": "Recherche Web", + "settings.permissions.tool.websearch.description": "Rechercher sur le web", + "settings.permissions.tool.codesearch.title": "Recherche de code", + "settings.permissions.tool.codesearch.description": "Rechercher du code sur le web", + "settings.permissions.tool.external_directory.title": "Répertoire externe", + "settings.permissions.tool.external_directory.description": "Accéder aux fichiers en dehors du répertoire du projet", + "settings.permissions.tool.doom_loop.title": "Boucle infernale", + "settings.permissions.tool.doom_loop.description": "Détecter les appels d'outils répétés avec une entrée identique", + + "session.delete.failed.title": "Échec de la suppression de la session", + "session.delete.title": "Supprimer la session", + "session.delete.confirm": 'Supprimer la session "{{name}}" ?', + "session.delete.button": "Supprimer la session", + + "workspace.new": "Nouvel espace de travail", + "workspace.type.local": "local", + "workspace.type.sandbox": "bac à sable", + "workspace.create.failed.title": "Échec de la création de l'espace de travail", + "workspace.delete.failed.title": "Échec de la suppression de l'espace de travail", + "workspace.resetting.title": "Réinitialisation de l'espace de travail", + "workspace.resetting.description": "Cela peut prendre une minute.", + "workspace.reset.failed.title": "Échec de la réinitialisation de l'espace de travail", + "workspace.reset.success.title": "Espace de travail réinitialisé", + "workspace.reset.success.description": "L'espace de travail correspond maintenant à la branche par défaut.", + "workspace.status.checking": "Vérification des modifications non fusionnées...", + "workspace.status.error": "Impossible de vérifier le statut git.", + "workspace.status.clean": "Aucune modification non fusionnée détectée.", + "workspace.status.dirty": "Modifications non fusionnées détectées dans cet espace de travail.", + "workspace.delete.title": "Supprimer l'espace de travail", + "workspace.delete.confirm": 'Supprimer l\'espace de travail "{{name}}" ?', + "workspace.delete.button": "Supprimer l'espace de travail", + "workspace.reset.title": "Réinitialiser l'espace de travail", + "workspace.reset.confirm": 'Réinitialiser l\'espace de travail "{{name}}" ?', + "workspace.reset.button": "Réinitialiser l'espace de travail", + "workspace.reset.archived.none": "Aucune session active ne sera archivée.", + "workspace.reset.archived.one": "1 session sera archivée.", + "workspace.reset.archived.many": "{{count}} sessions seront archivées.", + "workspace.reset.note": "Cela réinitialisera l'espace de travail pour correspondre à la branche par défaut.", +} diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts new file mode 100644 index 00000000000..821cda762e9 --- /dev/null +++ b/packages/app/src/i18n/ja.ts @@ -0,0 +1,577 @@ +export const dict = { + "command.category.suggested": "おすすめ", + "command.category.view": "表示", + "command.category.project": "プロジェクト", + "command.category.provider": "プロバイダー", + "command.category.server": "サーバー", + "command.category.session": "セッション", + "command.category.theme": "テーマ", + "command.category.language": "言語", + "command.category.file": "ファイル", + "command.category.terminal": "ターミナル", + "command.category.model": "モデル", + "command.category.mcp": "MCP", + "command.category.agent": "エージェント", + "command.category.permissions": "権限", + "command.category.workspace": "ワークスペース", + + "theme.scheme.system": "システム", + "theme.scheme.light": "ライト", + "theme.scheme.dark": "ダーク", + + "command.sidebar.toggle": "サイドバーの切り替え", + "command.project.open": "プロジェクトを開く", + "command.provider.connect": "プロバイダーに接続", + "command.server.switch": "サーバーの切り替え", + "command.session.previous": "前のセッション", + "command.session.next": "次のセッション", + "command.session.archive": "セッションをアーカイブ", + + "command.palette": "コマンドパレット", + + "command.theme.cycle": "テーマの切り替え", + "command.theme.set": "テーマを使用: {{theme}}", + "command.theme.scheme.cycle": "配色の切り替え", + "command.theme.scheme.set": "配色を使用: {{scheme}}", + + "command.language.cycle": "言語の切り替え", + "command.language.set": "言語を使用: {{language}}", + + "command.session.new": "新しいセッション", + "command.file.open": "ファイルを開く", + "command.file.open.description": "ファイルとコマンドを検索", + "command.terminal.toggle": "ターミナルの切り替え", + "command.review.toggle": "レビューの切り替え", + "command.terminal.new": "新しいターミナル", + "command.terminal.new.description": "新しいターミナルタブを作成", + "command.steps.toggle": "ステップの切り替え", + "command.steps.toggle.description": "現在のメッセージのステップを表示または非表示", + "command.message.previous": "前のメッセージ", + "command.message.previous.description": "前のユーザーメッセージに移動", + "command.message.next": "次のメッセージ", + "command.message.next.description": "次のユーザーメッセージに移動", + "command.model.choose": "モデルを選択", + "command.model.choose.description": "別のモデルを選択", + "command.mcp.toggle": "MCPの切り替え", + "command.mcp.toggle.description": "MCPを切り替える", + "command.agent.cycle": "エージェントの切り替え", + "command.agent.cycle.description": "次のエージェントに切り替え", + "command.agent.cycle.reverse": "エージェントを逆順に切り替え", + "command.agent.cycle.reverse.description": "前のエージェントに切り替え", + "command.model.variant.cycle": "思考レベルの切り替え", + "command.model.variant.cycle.description": "次の思考レベルに切り替え", + "command.permissions.autoaccept.enable": "編集を自動承認", + "command.permissions.autoaccept.disable": "編集の自動承認を停止", + "command.session.undo": "元に戻す", + "command.session.undo.description": "最後のメッセージを元に戻す", + "command.session.redo": "やり直す", + "command.session.redo.description": "元に戻したメッセージをやり直す", + "command.session.compact": "セッションを圧縮", + "command.session.compact.description": "セッションを要約してコンテキストサイズを削減", + "command.session.fork": "メッセージからフォーク", + "command.session.fork.description": "以前のメッセージから新しいセッションを作成", + "command.session.share": "セッションを共有", + "command.session.share.description": "このセッションを共有しURLをクリップボードにコピー", + "command.session.unshare": "セッションの共有を停止", + "command.session.unshare.description": "このセッションの共有を停止", + + "palette.search.placeholder": "ファイルとコマンドを検索", + "palette.empty": "結果が見つかりません", + "palette.group.commands": "コマンド", + "palette.group.files": "ファイル", + + "dialog.provider.search.placeholder": "プロバイダーを検索", + "dialog.provider.empty": "プロバイダーが見つかりません", + "dialog.provider.group.popular": "人気", + "dialog.provider.group.other": "その他", + "dialog.provider.tag.recommended": "推奨", + "dialog.provider.anthropic.note": "Claude Pro/MaxまたはAPIキーで接続", + + "dialog.model.select.title": "モデルを選択", + "dialog.model.search.placeholder": "モデルを検索", + "dialog.model.empty": "モデルが見つかりません", + "dialog.model.manage": "モデルを管理", + "dialog.model.manage.description": "モデルセレクターに表示するモデルをカスタマイズします。", + + "dialog.model.unpaid.freeModels.title": "OpenCodeが提供する無料モデル", + "dialog.model.unpaid.addMore.title": "人気のプロバイダーからモデルを追加", + + "dialog.provider.viewAll": "すべてのプロバイダーを表示", + + "provider.connect.title": "{{provider}}を接続", + "provider.connect.title.anthropicProMax": "Claude Pro/Maxでログイン", + "provider.connect.selectMethod": "{{provider}}のログイン方法を選択してください。", + "provider.connect.method.apiKey": "APIキー", + "provider.connect.status.inProgress": "認証中...", + "provider.connect.status.waiting": "認証を待機中...", + "provider.connect.status.failed": "認証に失敗しました: {{error}}", + "provider.connect.apiKey.description": + "{{provider}}のAPIキーを入力してアカウントを接続し、OpenCodeで{{provider}}モデルを使用します。", + "provider.connect.apiKey.label": "{{provider}} APIキー", + "provider.connect.apiKey.placeholder": "APIキー", + "provider.connect.apiKey.required": "APIキーが必要です", + "provider.connect.opencodeZen.line1": + "OpenCode Zenは、コーディングエージェント向けに最適化された信頼性の高いモデルへのアクセスを提供します。", + "provider.connect.opencodeZen.line2": "1つのAPIキーで、Claude、GPT、Gemini、GLMなどのモデルにアクセスできます。", + "provider.connect.opencodeZen.visit.prefix": " ", + "provider.connect.opencodeZen.visit.suffix": " にアクセスしてAPIキーを取得してください。", + "provider.connect.oauth.code.visit.prefix": " ", + "provider.connect.oauth.code.visit.link": "このリンク", + "provider.connect.oauth.code.visit.suffix": + " にアクセスして認証コードを取得し、アカウントを接続してOpenCodeで{{provider}}モデルを使用してください。", + "provider.connect.oauth.code.label": "{{method}} 認証コード", + "provider.connect.oauth.code.placeholder": "認証コード", + "provider.connect.oauth.code.required": "認証コードが必要です", + "provider.connect.oauth.code.invalid": "無効な認証コード", + "provider.connect.oauth.auto.visit.prefix": " ", + "provider.connect.oauth.auto.visit.link": "このリンク", + "provider.connect.oauth.auto.visit.suffix": + " にアクセスし、以下のコードを入力してアカウントを接続し、OpenCodeで{{provider}}モデルを使用してください。", + "provider.connect.oauth.auto.confirmationCode": "確認コード", + "provider.connect.toast.connected.title": "{{provider}}が接続されました", + "provider.connect.toast.connected.description": "{{provider}}モデルが使用可能になりました。", + + "model.tag.free": "無料", + "model.tag.latest": "最新", + + "common.search.placeholder": "検索", + "common.goBack": "戻る", + "common.loading": "読み込み中", + "common.cancel": "キャンセル", + "common.submit": "送信", + "common.save": "保存", + "common.saving": "保存中...", + "common.default": "デフォルト", + "common.attachment": "添付ファイル", + + "prompt.placeholder.shell": "シェルコマンドを入力...", + "prompt.placeholder.normal": '何でも聞いてください... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "escで終了", + + "prompt.example.1": "コードベースのTODOを修正", + "prompt.example.2": "このプロジェクトの技術スタックは何ですか?", + "prompt.example.3": "壊れたテストを修正", + "prompt.example.4": "認証の仕組みを説明して", + "prompt.example.5": "セキュリティの脆弱性を見つけて修正", + "prompt.example.6": "ユーザーサービスのユニットテストを追加", + "prompt.example.7": "この関数を読みやすくリファクタリング", + "prompt.example.8": "このエラーはどういう意味ですか?", + "prompt.example.9": "この問題のデバッグを手伝って", + "prompt.example.10": "APIドキュメントを生成", + "prompt.example.11": "データベースクエリを最適化", + "prompt.example.12": "入力バリデーションを追加", + "prompt.example.13": "〜の新しいコンポーネントを作成", + "prompt.example.14": "このプロジェクトをデプロイするには?", + "prompt.example.15": "ベストプラクティスの観点でコードをレビュー", + "prompt.example.16": "この関数にエラーハンドリングを追加", + "prompt.example.17": "この正規表現パターンを説明して", + "prompt.example.18": "これをTypeScriptに変換", + "prompt.example.19": "コードベース全体にログを追加", + "prompt.example.20": "古い依存関係はどれですか?", + "prompt.example.21": "マイグレーションスクリプトの作成を手伝って", + "prompt.example.22": "このエンドポイントにキャッシュを実装", + "prompt.example.23": "このリストにページネーションを追加", + "prompt.example.24": "〜のCLIコマンドを作成", + "prompt.example.25": "ここでは環境変数はどう機能しますか?", + + "prompt.popover.emptyResults": "一致する結果がありません", + "prompt.popover.emptyCommands": "一致するコマンドがありません", + "prompt.dropzone.label": "画像またはPDFをここにドロップ", + "prompt.slash.badge.custom": "カスタム", + "prompt.context.active": "アクティブ", + "prompt.context.includeActiveFile": "アクティブなファイルを含める", + "prompt.context.removeActiveFile": "コンテキストからアクティブなファイルを削除", + "prompt.context.removeFile": "コンテキストからファイルを削除", + "prompt.action.attachFile": "ファイルを添付", + "prompt.attachment.remove": "添付ファイルを削除", + "prompt.action.send": "送信", + "prompt.action.stop": "停止", + + "prompt.toast.pasteUnsupported.title": "サポートされていない貼り付け", + "prompt.toast.pasteUnsupported.description": "ここでは画像またはPDFのみ貼り付け可能です。", + "prompt.toast.modelAgentRequired.title": "エージェントとモデルを選択", + "prompt.toast.modelAgentRequired.description": "プロンプトを送信する前にエージェントとモデルを選択してください。", + "prompt.toast.worktreeCreateFailed.title": "ワークツリーの作成に失敗しました", + "prompt.toast.sessionCreateFailed.title": "セッションの作成に失敗しました", + "prompt.toast.shellSendFailed.title": "シェルコマンドの送信に失敗しました", + "prompt.toast.commandSendFailed.title": "コマンドの送信に失敗しました", + "prompt.toast.promptSendFailed.title": "プロンプトの送信に失敗しました", + + "dialog.mcp.title": "MCP", + "dialog.mcp.description": "{{total}}個中{{enabled}}個が有効", + "dialog.mcp.empty": "MCPが設定されていません", + + "mcp.status.connected": "接続済み", + "mcp.status.failed": "失敗", + "mcp.status.needs_auth": "認証が必要", + "mcp.status.disabled": "無効", + + "dialog.fork.empty": "フォーク元のメッセージがありません", + + "dialog.directory.search.placeholder": "フォルダを検索", + "dialog.directory.empty": "フォルダが見つかりません", + + "dialog.server.title": "サーバー", + "dialog.server.description": "このアプリが接続するOpenCodeサーバーを切り替えます。", + "dialog.server.search.placeholder": "サーバーを検索", + "dialog.server.empty": "サーバーはまだありません", + "dialog.server.add.title": "サーバーを追加", + "dialog.server.add.url": "サーバーURL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "サーバーに接続できませんでした", + "dialog.server.add.checking": "確認中...", + "dialog.server.add.button": "追加", + "dialog.server.default.title": "デフォルトサーバー", + "dialog.server.default.description": + "ローカルサーバーを起動する代わりに、アプリ起動時にこのサーバーに接続します。再起動が必要です。", + "dialog.server.default.none": "サーバーが選択されていません", + "dialog.server.default.set": "現在のサーバーをデフォルトに設定", + "dialog.server.default.clear": "クリア", + "dialog.server.action.remove": "サーバーを削除", + + "dialog.project.edit.title": "プロジェクトを編集", + "dialog.project.edit.name": "名前", + "dialog.project.edit.icon": "アイコン", + "dialog.project.edit.icon.alt": "プロジェクトアイコン", + "dialog.project.edit.icon.hint": "クリックまたは画像をドラッグ", + "dialog.project.edit.icon.recommended": "推奨: 128x128px", + "dialog.project.edit.color": "色", + "dialog.project.edit.color.select": "{{color}}の色を選択", + + "context.breakdown.title": "コンテキストの内訳", + "context.breakdown.note": '入力トークンのおおよその内訳です。"その他"にはツールの定義やオーバーヘッドが含まれます。', + "context.breakdown.system": "システム", + "context.breakdown.user": "ユーザー", + "context.breakdown.assistant": "アシスタント", + "context.breakdown.tool": "ツール呼び出し", + "context.breakdown.other": "その他", + + "context.systemPrompt.title": "システムプロンプト", + "context.rawMessages.title": "生のメッセージ", + + "context.stats.session": "セッション", + "context.stats.messages": "メッセージ", + "context.stats.provider": "プロバイダー", + "context.stats.model": "モデル", + "context.stats.limit": "コンテキスト制限", + "context.stats.totalTokens": "総トークン数", + "context.stats.usage": "使用量", + "context.stats.inputTokens": "入力トークン", + "context.stats.outputTokens": "出力トークン", + "context.stats.reasoningTokens": "推論トークン", + "context.stats.cacheTokens": "キャッシュトークン (読込/書込)", + "context.stats.userMessages": "ユーザーメッセージ", + "context.stats.assistantMessages": "アシスタントメッセージ", + "context.stats.totalCost": "総コスト", + "context.stats.sessionCreated": "セッション作成日時", + "context.stats.lastActivity": "最終アクティビティ", + + "context.usage.tokens": "トークン", + "context.usage.usage": "使用量", + "context.usage.cost": "コスト", + "context.usage.clickToView": "クリックしてコンテキストを表示", + "context.usage.view": "コンテキスト使用量を表示", + + "language.en": "英語", + "language.zh": "中国語(簡体字)", + "language.zht": "中国語(繁体字)", + "language.ko": "韓国語", + "language.de": "ドイツ語", + "language.es": "スペイン語", + "language.fr": "フランス語", + "language.ja": "日本語", + "language.da": "デンマーク語", + "language.ru": "ロシア語", + "language.pl": "ポーランド語", + "language.ar": "アラビア語", + "language.no": "ノルウェー語", + "language.br": "ポルトガル語(ブラジル)", + + "toast.language.title": "言語", + "toast.language.description": "{{language}}に切り替えました", + + "toast.theme.title": "テーマが切り替わりました", + "toast.scheme.title": "配色", + + "toast.permissions.autoaccept.on.title": "編集を自動承認中", + "toast.permissions.autoaccept.on.description": "編集と書き込みの権限は自動的に承認されます", + "toast.permissions.autoaccept.off.title": "編集の自動承認を停止しました", + "toast.permissions.autoaccept.off.description": "編集と書き込みの権限には承認が必要です", + + "toast.model.none.title": "モデルが選択されていません", + "toast.model.none.description": "このセッションを要約するにはプロバイダーを接続してください", + + "toast.file.loadFailed.title": "ファイルの読み込みに失敗しました", + + "toast.session.share.copyFailed.title": "URLのコピーに失敗しました", + "toast.session.share.success.title": "セッションを共有しました", + "toast.session.share.success.description": "共有URLをクリップボードにコピーしました!", + "toast.session.share.failed.title": "セッションの共有に失敗しました", + "toast.session.share.failed.description": "セッションの共有中にエラーが発生しました", + + "toast.session.unshare.success.title": "セッションの共有を解除しました", + "toast.session.unshare.success.description": "セッションの共有解除に成功しました!", + "toast.session.unshare.failed.title": "セッションの共有解除に失敗しました", + "toast.session.unshare.failed.description": "セッションの共有解除中にエラーが発生しました", + + "toast.session.listFailed.title": "{{project}}のセッション読み込みに失敗しました", + + "toast.update.title": "アップデートが利用可能です", + "toast.update.description": "OpenCodeの新しいバージョン ({{version}}) がインストール可能です。", + "toast.update.action.installRestart": "インストールして再起動", + "toast.update.action.notYet": "今はしない", + + "error.page.title": "問題が発生しました", + "error.page.description": "アプリケーションの読み込み中にエラーが発生しました。", + "error.page.details.label": "エラー詳細", + "error.page.action.restart": "再起動", + "error.page.action.checking": "確認中...", + "error.page.action.checkUpdates": "アップデートを確認", + "error.page.action.updateTo": "{{version}}にアップデート", + "error.page.report.prefix": "このエラーをOpenCodeチームに報告してください: ", + "error.page.report.discord": "Discord", + "error.page.version": "バージョン: {{version}}", + + "error.dev.rootNotFound": + "ルート要素が見つかりません。index.htmlに追加するのを忘れていませんか?またはid属性のスペルが間違っていませんか?", + + "error.globalSync.connectFailed": "サーバーに接続できませんでした。`{{url}}`でサーバーが実行されていますか?", + + "error.chain.unknown": "不明なエラー", + "error.chain.causedBy": "原因:", + "error.chain.apiError": "APIエラー", + "error.chain.status": "ステータス: {{status}}", + "error.chain.retryable": "再試行可能: {{retryable}}", + "error.chain.responseBody": "レスポンス本文:\n{{body}}", + "error.chain.didYouMean": "もしかして: {{suggestions}}", + "error.chain.modelNotFound": "モデルが見つかりません: {{provider}}/{{model}}", + "error.chain.checkConfig": "config (opencode.json) のプロバイダー/モデル名を確認してください", + "error.chain.mcpFailed": 'MCPサーバー "{{name}}" が失敗しました。注意: OpenCodeはまだMCP認証をサポートしていません。', + "error.chain.providerAuthFailed": "プロバイダー認証に失敗しました ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'プロバイダー "{{provider}}" の初期化に失敗しました。認証情報と設定を確認してください。', + "error.chain.configJsonInvalid": "{{path}} の設定ファイルは有効なJSON(C)ではありません", + "error.chain.configJsonInvalidWithMessage": "{{path}} の設定ファイルは有効なJSON(C)ではありません: {{message}}", + "error.chain.configDirectoryTypo": + '{{path}} 内のディレクトリ "{{dir}}" は無効です。"{{suggestion}}" に名前を変更するか削除してください。これはよくあるタイプミスです。', + "error.chain.configFrontmatterError": "{{path}} のフロントマターの解析に失敗しました:\n{{message}}", + "error.chain.configInvalid": "{{path}} の設定ファイルが無効です", + "error.chain.configInvalidWithMessage": "{{path}} の設定ファイルが無効です: {{message}}", + + "notification.permission.title": "権限が必要です", + "notification.permission.description": "{{projectName}} の {{sessionTitle}} が権限を必要としています", + "notification.question.title": "質問", + "notification.question.description": "{{projectName}} の {{sessionTitle}} から質問があります", + "notification.action.goToSession": "セッションへ移動", + + "notification.session.responseReady.title": "応答の準備ができました", + "notification.session.error.title": "セッションエラー", + "notification.session.error.fallbackDescription": "エラーが発生しました", + + "home.recentProjects": "最近のプロジェクト", + "home.empty.title": "最近のプロジェクトはありません", + "home.empty.description": "ローカルプロジェクトを開いて始めましょう", + + "session.tab.session": "セッション", + "session.tab.review": "レビュー", + "session.tab.context": "コンテキスト", + "session.panel.reviewAndFiles": "レビューとファイル", + "session.review.filesChanged": "{{count}} ファイル変更", + "session.review.loadingChanges": "変更を読み込み中...", + "session.review.empty": "このセッションでの変更はまだありません", + "session.messages.renderEarlier": "以前のメッセージを表示", + "session.messages.loadingEarlier": "以前のメッセージを読み込み中...", + "session.messages.loadEarlier": "以前のメッセージを読み込む", + "session.messages.loading": "メッセージを読み込み中...", + + "session.context.addToContext": "{{selection}}をコンテキストに追加", + + "session.new.worktree.main": "メインブランチ", + "session.new.worktree.mainWithBranch": "メインブランチ ({{branch}})", + "session.new.worktree.create": "新しいワークツリーを作成", + "session.new.lastModified": "最終更新", + + "session.header.search.placeholder": "{{project}}を検索", + "session.header.searchFiles": "ファイルを検索", + + "session.share.popover.title": "ウェブで公開", + "session.share.popover.description.shared": + "このセッションはウェブで公開されています。リンクを知っている人なら誰でもアクセスできます。", + "session.share.popover.description.unshared": + "セッションをウェブで公開します。リンクを知っている人なら誰でもアクセスできるようになります。", + "session.share.action.share": "共有", + "session.share.action.publish": "公開", + "session.share.action.publishing": "公開中...", + "session.share.action.unpublish": "非公開にする", + "session.share.action.unpublishing": "非公開にしています...", + "session.share.action.view": "表示", + "session.share.copy.copied": "コピーしました", + "session.share.copy.copyLink": "リンクをコピー", + + "lsp.tooltip.none": "LSPサーバーなし", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "プロンプトを読み込み中...", + "terminal.loading": "ターミナルを読み込み中...", + "terminal.title": "ターミナル", + "terminal.title.numbered": "ターミナル {{number}}", + "terminal.close": "ターミナルを閉じる", + + "common.closeTab": "タブを閉じる", + "common.dismiss": "閉じる", + "common.requestFailed": "リクエスト失敗", + "common.moreOptions": "その他のオプション", + "common.learnMore": "詳細", + "common.rename": "名前変更", + "common.reset": "リセット", + "common.archive": "アーカイブ", + "common.delete": "削除", + "common.close": "閉じる", + "common.edit": "編集", + "common.loadMore": "さらに読み込む", + + "sidebar.nav.projectsAndSessions": "プロジェクトとセッション", + "sidebar.settings": "設定", + "sidebar.help": "ヘルプ", + "sidebar.workspaces.enable": "ワークスペースを有効化", + "sidebar.workspaces.disable": "ワークスペースを無効化", + "sidebar.gettingStarted.title": "はじめに", + "sidebar.gettingStarted.line1": "OpenCodeには無料モデルが含まれているため、すぐに開始できます。", + "sidebar.gettingStarted.line2": "プロバイダーを接続して、Claude、GPT、Geminiなどのモデルを使用できます。", + "sidebar.project.recentSessions": "最近のセッション", + "sidebar.project.viewAllSessions": "すべてのセッションを表示", + + "settings.section.desktop": "デスクトップ", + "settings.tab.general": "一般", + "settings.tab.shortcuts": "ショートカット", + + "settings.general.section.appearance": "外観", + "settings.general.section.notifications": "システム通知", + "settings.general.section.sounds": "効果音", + + "settings.general.row.language.title": "言語", + "settings.general.row.language.description": "OpenCodeの表示言語を変更します", + "settings.general.row.appearance.title": "外観", + "settings.general.row.appearance.description": "デバイスでのOpenCodeの表示をカスタマイズします", + "settings.general.row.theme.title": "テーマ", + "settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。", + "settings.general.row.font.title": "フォント", + "settings.general.row.font.description": "コードブロックで使用する等幅フォントをカスタマイズします", + + "settings.general.notifications.agent.title": "エージェント", + "settings.general.notifications.agent.description": + "エージェントが完了したか、注意が必要な場合にシステム通知を表示します", + "settings.general.notifications.permissions.title": "権限", + "settings.general.notifications.permissions.description": "権限が必要な場合にシステム通知を表示します", + "settings.general.notifications.errors.title": "エラー", + "settings.general.notifications.errors.description": "エラーが発生した場合にシステム通知を表示します", + + "settings.general.sounds.agent.title": "エージェント", + "settings.general.sounds.agent.description": "エージェントが完了したか、注意が必要な場合に音を再生します", + "settings.general.sounds.permissions.title": "権限", + "settings.general.sounds.permissions.description": "権限が必要な場合に音を再生します", + "settings.general.sounds.errors.title": "エラー", + "settings.general.sounds.errors.description": "エラーが発生した場合に音を再生します", + + "settings.shortcuts.title": "キーボードショートカット", + "settings.shortcuts.reset.button": "デフォルトにリセット", + "settings.shortcuts.reset.toast.title": "ショートカットをリセットしました", + "settings.shortcuts.reset.toast.description": "キーボードショートカットがデフォルトにリセットされました。", + "settings.shortcuts.conflict.title": "ショートカットは既に使用されています", + "settings.shortcuts.conflict.description": "{{keybind}} は既に {{titles}} に割り当てられています。", + "settings.shortcuts.unassigned": "未割り当て", + "settings.shortcuts.pressKeys": "キーを押してください", + "settings.shortcuts.search.placeholder": "ショートカットを検索", + "settings.shortcuts.search.empty": "ショートカットが見つかりません", + + "settings.shortcuts.group.general": "一般", + "settings.shortcuts.group.session": "セッション", + "settings.shortcuts.group.navigation": "ナビゲーション", + "settings.shortcuts.group.modelAndAgent": "モデルとエージェント", + "settings.shortcuts.group.terminal": "ターミナル", + "settings.shortcuts.group.prompt": "プロンプト", + + "settings.providers.title": "プロバイダー", + "settings.providers.description": "プロバイダー設定はここで構成できます。", + "settings.models.title": "モデル", + "settings.models.description": "モデル設定はここで構成できます。", + "settings.agents.title": "エージェント", + "settings.agents.description": "エージェント設定はここで構成できます。", + "settings.commands.title": "コマンド", + "settings.commands.description": "コマンド設定はここで構成できます。", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP設定はここで構成できます。", + + "settings.permissions.title": "権限", + "settings.permissions.description": "サーバーがデフォルトで使用できるツールを制御します。", + "settings.permissions.section.tools": "ツール", + "settings.permissions.toast.updateFailed.title": "権限の更新に失敗しました", + + "settings.permissions.action.allow": "許可", + "settings.permissions.action.ask": "確認", + "settings.permissions.action.deny": "拒否", + + "settings.permissions.tool.read.title": "読み込み", + "settings.permissions.tool.read.description": "ファイルの読み込み (ファイルパスに一致)", + "settings.permissions.tool.edit.title": "編集", + "settings.permissions.tool.edit.description": "ファイルの変更(編集、書き込み、パッチ、複数編集を含む)", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Globパターンを使用したファイルの一致", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "正規表現を使用したファイル内容の検索", + "settings.permissions.tool.list.title": "リスト", + "settings.permissions.tool.list.description": "ディレクトリ内のファイル一覧表示", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "シェルコマンドの実行", + "settings.permissions.tool.task.title": "タスク", + "settings.permissions.tool.task.description": "サブエージェントの起動", + "settings.permissions.tool.skill.title": "スキル", + "settings.permissions.tool.skill.description": "名前によるスキルの読み込み", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "言語サーバークエリの実行", + "settings.permissions.tool.todoread.title": "Todo読み込み", + "settings.permissions.tool.todoread.description": "Todoリストの読み込み", + "settings.permissions.tool.todowrite.title": "Todo書き込み", + "settings.permissions.tool.todowrite.description": "Todoリストの更新", + "settings.permissions.tool.webfetch.title": "Web Fetch", + "settings.permissions.tool.webfetch.description": "URLからコンテンツを取得", + "settings.permissions.tool.websearch.title": "Web Search", + "settings.permissions.tool.websearch.description": "ウェブを検索", + "settings.permissions.tool.codesearch.title": "Code Search", + "settings.permissions.tool.codesearch.description": "ウェブ上のコードを検索", + "settings.permissions.tool.external_directory.title": "外部ディレクトリ", + "settings.permissions.tool.external_directory.description": "プロジェクトディレクトリ外のファイルへのアクセス", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "同一入力による繰り返しのツール呼び出しを検出", + + "session.delete.failed.title": "セッションの削除に失敗しました", + "session.delete.title": "セッションの削除", + "session.delete.confirm": 'セッション "{{name}}" を削除しますか?', + "session.delete.button": "セッションを削除", + + "workspace.new": "新しいワークスペース", + "workspace.type.local": "ローカル", + "workspace.type.sandbox": "サンドボックス", + "workspace.create.failed.title": "ワークスペースの作成に失敗しました", + "workspace.delete.failed.title": "ワークスペースの削除に失敗しました", + "workspace.resetting.title": "ワークスペースをリセット中", + "workspace.resetting.description": "これには少し時間がかかる場合があります。", + "workspace.reset.failed.title": "ワークスペースのリセットに失敗しました", + "workspace.reset.success.title": "ワークスペースをリセットしました", + "workspace.reset.success.description": "ワークスペースはデフォルトブランチと一致しています。", + "workspace.status.checking": "未マージの変更を確認中...", + "workspace.status.error": "gitステータスを確認できません。", + "workspace.status.clean": "未マージの変更は検出されませんでした。", + "workspace.status.dirty": "このワークスペースで未マージの変更が検出されました。", + "workspace.delete.title": "ワークスペースの削除", + "workspace.delete.confirm": 'ワークスペース "{{name}}" を削除しますか?', + "workspace.delete.button": "ワークスペースを削除", + "workspace.reset.title": "ワークスペースのリセット", + "workspace.reset.confirm": 'ワークスペース "{{name}}" をリセットしますか?', + "workspace.reset.button": "ワークスペースをリセット", + "workspace.reset.archived.none": "アクティブなセッションはアーカイブされません。", + "workspace.reset.archived.one": "1つのセッションがアーカイブされます。", + "workspace.reset.archived.many": "{{count}}個のセッションがアーカイブされます。", + "workspace.reset.note": "これにより、ワークスペースはデフォルトブランチと一致するようにリセットされます。", +} diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts new file mode 100644 index 00000000000..69a5fd65889 --- /dev/null +++ b/packages/app/src/i18n/ko.ts @@ -0,0 +1,578 @@ +import { dict as en } from "./en" + +type Keys = keyof typeof en + +export const dict = { + "command.category.suggested": "추천", + "command.category.view": "보기", + "command.category.project": "프로젝트", + "command.category.provider": "공급자", + "command.category.server": "서버", + "command.category.session": "세션", + "command.category.theme": "테마", + "command.category.language": "언어", + "command.category.file": "파일", + "command.category.terminal": "터미널", + "command.category.model": "모델", + "command.category.mcp": "MCP", + "command.category.agent": "에이전트", + "command.category.permissions": "권한", + "command.category.workspace": "작업 공간", + + "theme.scheme.system": "시스템", + "theme.scheme.light": "라이트", + "theme.scheme.dark": "다크", + + "command.sidebar.toggle": "사이드바 토글", + "command.project.open": "프로젝트 열기", + "command.provider.connect": "공급자 연결", + "command.server.switch": "서버 전환", + "command.session.previous": "이전 세션", + "command.session.next": "다음 세션", + "command.session.archive": "세션 보관", + + "command.palette": "명령 팔레트", + + "command.theme.cycle": "테마 순환", + "command.theme.set": "테마 사용: {{theme}}", + "command.theme.scheme.cycle": "색상 테마 순환", + "command.theme.scheme.set": "색상 테마 사용: {{scheme}}", + + "command.language.cycle": "언어 순환", + "command.language.set": "언어 사용: {{language}}", + + "command.session.new": "새 세션", + "command.file.open": "파일 열기", + "command.file.open.description": "파일 및 명령어 검색", + "command.terminal.toggle": "터미널 토글", + "command.review.toggle": "검토 토글", + "command.terminal.new": "새 터미널", + "command.terminal.new.description": "새 터미널 탭 생성", + "command.steps.toggle": "단계 토글", + "command.steps.toggle.description": "현재 메시지의 단계 표시/숨기기", + "command.message.previous": "이전 메시지", + "command.message.previous.description": "이전 사용자 메시지로 이동", + "command.message.next": "다음 메시지", + "command.message.next.description": "다음 사용자 메시지로 이동", + "command.model.choose": "모델 선택", + "command.model.choose.description": "다른 모델 선택", + "command.mcp.toggle": "MCP 토글", + "command.mcp.toggle.description": "MCP 토글", + "command.agent.cycle": "에이전트 순환", + "command.agent.cycle.description": "다음 에이전트로 전환", + "command.agent.cycle.reverse": "에이전트 역순환", + "command.agent.cycle.reverse.description": "이전 에이전트로 전환", + "command.model.variant.cycle": "생각 수준 순환", + "command.model.variant.cycle.description": "다음 생각 수준으로 전환", + "command.permissions.autoaccept.enable": "편집 자동 수락", + "command.permissions.autoaccept.disable": "편집 자동 수락 중지", + "command.session.undo": "실행 취소", + "command.session.undo.description": "마지막 메시지 실행 취소", + "command.session.redo": "다시 실행", + "command.session.redo.description": "마지막 실행 취소된 메시지 다시 실행", + "command.session.compact": "세션 압축", + "command.session.compact.description": "컨텍스트 크기를 줄이기 위해 세션 요약", + "command.session.fork": "메시지에서 분기", + "command.session.fork.description": "이전 메시지에서 새 세션 생성", + "command.session.share": "세션 공유", + "command.session.share.description": "이 세션을 공유하고 URL을 클립보드에 복사", + "command.session.unshare": "세션 공유 중지", + "command.session.unshare.description": "이 세션 공유 중지", + + "palette.search.placeholder": "파일 및 명령어 검색", + "palette.empty": "결과 없음", + "palette.group.commands": "명령어", + "palette.group.files": "파일", + + "dialog.provider.search.placeholder": "공급자 검색", + "dialog.provider.empty": "공급자 없음", + "dialog.provider.group.popular": "인기", + "dialog.provider.group.other": "기타", + "dialog.provider.tag.recommended": "추천", + "dialog.provider.anthropic.note": "Claude Pro/Max 또는 API 키로 연결", + + "dialog.model.select.title": "모델 선택", + "dialog.model.search.placeholder": "모델 검색", + "dialog.model.empty": "모델 결과 없음", + "dialog.model.manage": "모델 관리", + "dialog.model.manage.description": "모델 선택기에 표시할 모델 사용자 지정", + + "dialog.model.unpaid.freeModels.title": "OpenCode에서 제공하는 무료 모델", + "dialog.model.unpaid.addMore.title": "인기 공급자의 모델 추가", + + "dialog.provider.viewAll": "모든 공급자 보기", + + "provider.connect.title": "{{provider}} 연결", + "provider.connect.title.anthropicProMax": "Claude Pro/Max로 로그인", + "provider.connect.selectMethod": "{{provider}} 로그인 방법 선택", + "provider.connect.method.apiKey": "API 키", + "provider.connect.status.inProgress": "인증 진행 중...", + "provider.connect.status.waiting": "인증 대기 중...", + "provider.connect.status.failed": "인증 실패: {{error}}", + "provider.connect.apiKey.description": + "{{provider}} API 키를 입력하여 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.", + "provider.connect.apiKey.label": "{{provider}} API 키", + "provider.connect.apiKey.placeholder": "API 키", + "provider.connect.apiKey.required": "API 키가 필요합니다", + "provider.connect.opencodeZen.line1": + "OpenCode Zen은 코딩 에이전트를 위해 최적화된 신뢰할 수 있는 엄선된 모델에 대한 액세스를 제공합니다.", + "provider.connect.opencodeZen.line2": "단일 API 키로 Claude, GPT, Gemini, GLM 등 다양한 모델에 액세스할 수 있습니다.", + "provider.connect.opencodeZen.visit.prefix": "", + "provider.connect.opencodeZen.visit.suffix": "를 방문하여 API 키를 받으세요.", + "provider.connect.oauth.code.visit.prefix": "", + "provider.connect.oauth.code.visit.link": "이 링크", + "provider.connect.oauth.code.visit.suffix": + "를 방문하여 인증 코드를 받아 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.", + "provider.connect.oauth.code.label": "{{method}} 인증 코드", + "provider.connect.oauth.code.placeholder": "인증 코드", + "provider.connect.oauth.code.required": "인증 코드가 필요합니다", + "provider.connect.oauth.code.invalid": "유효하지 않은 인증 코드", + "provider.connect.oauth.auto.visit.prefix": "", + "provider.connect.oauth.auto.visit.link": "이 링크", + "provider.connect.oauth.auto.visit.suffix": + "를 방문하고 아래 코드를 입력하여 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.", + "provider.connect.oauth.auto.confirmationCode": "확인 코드", + "provider.connect.toast.connected.title": "{{provider}} 연결됨", + "provider.connect.toast.connected.description": "이제 {{provider}} 모델을 사용할 수 있습니다.", + + "model.tag.free": "무료", + "model.tag.latest": "최신", + + "common.search.placeholder": "검색", + "common.goBack": "뒤로 가기", + "common.loading": "로딩 중", + "common.cancel": "취소", + "common.submit": "제출", + "common.save": "저장", + "common.saving": "저장 중...", + "common.default": "기본값", + "common.attachment": "첨부 파일", + + "prompt.placeholder.shell": "셸 명령어 입력...", + "prompt.placeholder.normal": '무엇이든 물어보세요... "{{example}}"', + "prompt.mode.shell": "셸", + "prompt.mode.shell.exit": "종료하려면 esc", + + "prompt.example.1": "코드베이스의 TODO 수정", + "prompt.example.2": "이 프로젝트의 기술 스택이 무엇인가요?", + "prompt.example.3": "고장 난 테스트 수정", + "prompt.example.4": "인증 작동 방식 설명", + "prompt.example.5": "보안 취약점 찾기 및 수정", + "prompt.example.6": "사용자 서비스에 단위 테스트 추가", + "prompt.example.7": "이 함수를 더 읽기 쉽게 리팩터링", + "prompt.example.8": "이 오류는 무엇을 의미하나요?", + "prompt.example.9": "이 문제 디버깅 도와줘", + "prompt.example.10": "API 문서 생성", + "prompt.example.11": "데이터베이스 쿼리 최적화", + "prompt.example.12": "입력 유효성 검사 추가", + "prompt.example.13": "...를 위한 새 컴포넌트 생성", + "prompt.example.14": "이 프로젝트를 어떻게 배포하나요?", + "prompt.example.15": "모범 사례를 기준으로 내 코드 검토", + "prompt.example.16": "이 함수에 오류 처리 추가", + "prompt.example.17": "이 정규식 패턴 설명", + "prompt.example.18": "이것을 TypeScript로 변환", + "prompt.example.19": "코드베이스 전체에 로깅 추가", + "prompt.example.20": "오래된 종속성은 무엇인가요?", + "prompt.example.21": "마이그레이션 스크립트 작성 도와줘", + "prompt.example.22": "이 엔드포인트에 캐싱 구현", + "prompt.example.23": "이 목록에 페이지네이션 추가", + "prompt.example.24": "...를 위한 CLI 명령어 생성", + "prompt.example.25": "여기서 환경 변수는 어떻게 작동하나요?", + + "prompt.popover.emptyResults": "일치하는 결과 없음", + "prompt.popover.emptyCommands": "일치하는 명령어 없음", + "prompt.dropzone.label": "이미지나 PDF를 여기에 드롭하세요", + "prompt.slash.badge.custom": "사용자 지정", + "prompt.context.active": "활성", + "prompt.context.includeActiveFile": "활성 파일 포함", + "prompt.context.removeActiveFile": "컨텍스트에서 활성 파일 제거", + "prompt.context.removeFile": "컨텍스트에서 파일 제거", + "prompt.action.attachFile": "파일 첨부", + "prompt.attachment.remove": "첨부 파일 제거", + "prompt.action.send": "전송", + "prompt.action.stop": "중지", + + "prompt.toast.pasteUnsupported.title": "지원되지 않는 붙여넣기", + "prompt.toast.pasteUnsupported.description": "이미지나 PDF만 붙여넣을 수 있습니다.", + "prompt.toast.modelAgentRequired.title": "에이전트 및 모델 선택", + "prompt.toast.modelAgentRequired.description": "프롬프트를 보내기 전에 에이전트와 모델을 선택하세요.", + "prompt.toast.worktreeCreateFailed.title": "작업 트리 생성 실패", + "prompt.toast.sessionCreateFailed.title": "세션 생성 실패", + "prompt.toast.shellSendFailed.title": "셸 명령 전송 실패", + "prompt.toast.commandSendFailed.title": "명령 전송 실패", + "prompt.toast.promptSendFailed.title": "프롬프트 전송 실패", + + "dialog.mcp.title": "MCP", + "dialog.mcp.description": "{{total}}개 중 {{enabled}}개 활성화됨", + "dialog.mcp.empty": "구성된 MCP 없음", + + "mcp.status.connected": "연결됨", + "mcp.status.failed": "실패", + "mcp.status.needs_auth": "인증 필요", + "mcp.status.disabled": "비활성화됨", + + "dialog.fork.empty": "분기할 메시지 없음", + + "dialog.directory.search.placeholder": "폴더 검색", + "dialog.directory.empty": "폴더 없음", + + "dialog.server.title": "서버", + "dialog.server.description": "이 앱이 연결할 OpenCode 서버를 전환합니다.", + "dialog.server.search.placeholder": "서버 검색", + "dialog.server.empty": "서버 없음", + "dialog.server.add.title": "서버 추가", + "dialog.server.add.url": "서버 URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "서버에 연결할 수 없습니다", + "dialog.server.add.checking": "확인 중...", + "dialog.server.add.button": "추가", + "dialog.server.default.title": "기본 서버", + "dialog.server.default.description": + "로컬 서버를 시작하는 대신 앱 실행 시 이 서버에 연결합니다. 다시 시작해야 합니다.", + "dialog.server.default.none": "선택된 서버 없음", + "dialog.server.default.set": "현재 서버를 기본값으로 설정", + "dialog.server.default.clear": "지우기", + "dialog.server.action.remove": "서버 제거", + + "dialog.project.edit.title": "프로젝트 편집", + "dialog.project.edit.name": "이름", + "dialog.project.edit.icon": "아이콘", + "dialog.project.edit.icon.alt": "프로젝트 아이콘", + "dialog.project.edit.icon.hint": "이미지를 클릭하거나 드래그하세요", + "dialog.project.edit.icon.recommended": "권장: 128x128px", + "dialog.project.edit.color": "색상", + "dialog.project.edit.color.select": "{{color}} 색상 선택", + + "context.breakdown.title": "컨텍스트 분석", + "context.breakdown.note": '입력 토큰의 대략적인 분석입니다. "기타"에는 도구 정의 및 오버헤드가 포함됩니다.', + "context.breakdown.system": "시스템", + "context.breakdown.user": "사용자", + "context.breakdown.assistant": "어시스턴트", + "context.breakdown.tool": "도구 호출", + "context.breakdown.other": "기타", + + "context.systemPrompt.title": "시스템 프롬프트", + "context.rawMessages.title": "원시 메시지", + + "context.stats.session": "세션", + "context.stats.messages": "메시지", + "context.stats.provider": "공급자", + "context.stats.model": "모델", + "context.stats.limit": "컨텍스트 제한", + "context.stats.totalTokens": "총 토큰", + "context.stats.usage": "사용량", + "context.stats.inputTokens": "입력 토큰", + "context.stats.outputTokens": "출력 토큰", + "context.stats.reasoningTokens": "추론 토큰", + "context.stats.cacheTokens": "캐시 토큰 (읽기/쓰기)", + "context.stats.userMessages": "사용자 메시지", + "context.stats.assistantMessages": "어시스턴트 메시지", + "context.stats.totalCost": "총 비용", + "context.stats.sessionCreated": "세션 생성됨", + "context.stats.lastActivity": "최근 활동", + + "context.usage.tokens": "토큰", + "context.usage.usage": "사용량", + "context.usage.cost": "비용", + "context.usage.clickToView": "컨텍스트를 보려면 클릭", + "context.usage.view": "컨텍스트 사용량 보기", + + "language.en": "영어", + "language.zh": "중국어 (간체)", + "language.zht": "중국어 (번체)", + "language.ko": "한국어", + "language.de": "독일어", + "language.es": "스페인어", + "language.fr": "프랑스어", + "language.ja": "일본어", + "language.da": "덴마크어", + "language.ru": "러시아어", + "language.pl": "폴란드어", + "language.ar": "아랍어", + "language.no": "노르웨이어", + "language.br": "포르투갈어 (브라질)", + + "toast.language.title": "언어", + "toast.language.description": "{{language}}(으)로 전환됨", + + "toast.theme.title": "테마 전환됨", + "toast.scheme.title": "색상 테마", + + "toast.permissions.autoaccept.on.title": "편집 자동 수락 중", + "toast.permissions.autoaccept.on.description": "편집 및 쓰기 권한이 자동으로 승인됩니다", + "toast.permissions.autoaccept.off.title": "편집 자동 수락 중지됨", + "toast.permissions.autoaccept.off.description": "편집 및 쓰기 권한 승인이 필요합니다", + + "toast.model.none.title": "선택된 모델 없음", + "toast.model.none.description": "이 세션을 요약하려면 공급자를 연결하세요", + + "toast.file.loadFailed.title": "파일 로드 실패", + + "toast.session.share.copyFailed.title": "URL 클립보드 복사 실패", + "toast.session.share.success.title": "세션 공유됨", + "toast.session.share.success.description": "공유 URL이 클립보드에 복사되었습니다!", + "toast.session.share.failed.title": "세션 공유 실패", + "toast.session.share.failed.description": "세션을 공유하는 동안 오류가 발생했습니다", + + "toast.session.unshare.success.title": "세션 공유 해제됨", + "toast.session.unshare.success.description": "세션 공유가 성공적으로 해제되었습니다!", + "toast.session.unshare.failed.title": "세션 공유 해제 실패", + "toast.session.unshare.failed.description": "세션 공유를 해제하는 동안 오류가 발생했습니다", + + "toast.session.listFailed.title": "{{project}}에 대한 세션을 로드하지 못했습니다", + + "toast.update.title": "업데이트 가능", + "toast.update.description": "OpenCode의 새 버전({{version}})을 설치할 수 있습니다.", + "toast.update.action.installRestart": "설치 및 다시 시작", + "toast.update.action.notYet": "나중에", + + "error.page.title": "문제가 발생했습니다", + "error.page.description": "애플리케이션을 로드하는 동안 오류가 발생했습니다.", + "error.page.details.label": "오류 세부 정보", + "error.page.action.restart": "다시 시작", + "error.page.action.checking": "확인 중...", + "error.page.action.checkUpdates": "업데이트 확인", + "error.page.action.updateTo": "{{version}} 버전으로 업데이트", + "error.page.report.prefix": "이 오류를 OpenCode 팀에 제보해 주세요: ", + "error.page.report.discord": "Discord", + "error.page.version": "버전: {{version}}", + + "error.dev.rootNotFound": + "루트 요소를 찾을 수 없습니다. index.html에 추가하는 것을 잊으셨나요? 또는 id 속성의 철자가 틀렸을 수 있습니다.", + + "error.globalSync.connectFailed": "서버에 연결할 수 없습니다. `{{url}}`에서 서버가 실행 중인가요?", + + "error.chain.unknown": "알 수 없는 오류", + "error.chain.causedBy": "원인:", + "error.chain.apiError": "API 오류", + "error.chain.status": "상태: {{status}}", + "error.chain.retryable": "재시도 가능: {{retryable}}", + "error.chain.responseBody": "응답 본문:\n{{body}}", + "error.chain.didYouMean": "혹시 {{suggestions}}을(를) 의미하셨나요?", + "error.chain.modelNotFound": "모델을 찾을 수 없음: {{provider}}/{{model}}", + "error.chain.checkConfig": "구성(opencode.json)의 공급자/모델 이름을 확인하세요", + "error.chain.mcpFailed": 'MCP 서버 "{{name}}" 실패. 참고: OpenCode는 아직 MCP 인증을 지원하지 않습니다.', + "error.chain.providerAuthFailed": "공급자 인증 실패 ({{provider}}): {{message}}", + "error.chain.providerInitFailed": '공급자 "{{provider}}" 초기화 실패. 자격 증명과 구성을 확인하세요.', + "error.chain.configJsonInvalid": "{{path}}의 구성 파일이 유효한 JSON(C)가 아닙니다", + "error.chain.configJsonInvalidWithMessage": "{{path}}의 구성 파일이 유효한 JSON(C)가 아닙니다: {{message}}", + "error.chain.configDirectoryTypo": + '{{path}}의 "{{dir}}" 디렉터리가 유효하지 않습니다. 디렉터리 이름을 "{{suggestion}}"으로 변경하거나 제거하세요. 이는 흔한 오타입니다.', + "error.chain.configFrontmatterError": "{{path}}의 frontmatter 파싱 실패:\n{{message}}", + "error.chain.configInvalid": "{{path}}의 구성 파일이 유효하지 않습니다", + "error.chain.configInvalidWithMessage": "{{path}}의 구성 파일이 유효하지 않습니다: {{message}}", + + "notification.permission.title": "권한 필요", + "notification.permission.description": "{{projectName}}의 {{sessionTitle}}에서 권한이 필요합니다", + "notification.question.title": "질문", + "notification.question.description": "{{projectName}}의 {{sessionTitle}}에서 질문이 있습니다", + "notification.action.goToSession": "세션으로 이동", + + "notification.session.responseReady.title": "응답 준비됨", + "notification.session.error.title": "세션 오류", + "notification.session.error.fallbackDescription": "오류가 발생했습니다", + + "home.recentProjects": "최근 프로젝트", + "home.empty.title": "최근 프로젝트 없음", + "home.empty.description": "로컬 프로젝트를 열어 시작하세요", + + "session.tab.session": "세션", + "session.tab.review": "검토", + "session.tab.context": "컨텍스트", + "session.panel.reviewAndFiles": "검토 및 파일", + "session.review.filesChanged": "{{count}}개 파일 변경됨", + "session.review.loadingChanges": "변경 사항 로드 중...", + "session.review.empty": "이 세션에 변경 사항이 아직 없습니다", + "session.messages.renderEarlier": "이전 메시지 렌더링", + "session.messages.loadingEarlier": "이전 메시지 로드 중...", + "session.messages.loadEarlier": "이전 메시지 로드", + "session.messages.loading": "메시지 로드 중...", + + "session.context.addToContext": "컨텍스트에 {{selection}} 추가", + + "session.new.worktree.main": "메인 브랜치", + "session.new.worktree.mainWithBranch": "메인 브랜치 ({{branch}})", + "session.new.worktree.create": "새 작업 트리 생성", + "session.new.lastModified": "최근 수정", + + "session.header.search.placeholder": "{{project}} 검색", + "session.header.searchFiles": "파일 검색", + + "session.share.popover.title": "웹에 게시", + "session.share.popover.description.shared": "이 세션은 웹에 공개되었습니다. 링크가 있는 누구나 액세스할 수 있습니다.", + "session.share.popover.description.unshared": + "세션을 웹에 공개적으로 공유합니다. 링크가 있는 누구나 액세스할 수 있습니다.", + "session.share.action.share": "공유", + "session.share.action.publish": "게시", + "session.share.action.publishing": "게시 중...", + "session.share.action.unpublish": "게시 취소", + "session.share.action.unpublishing": "게시 취소 중...", + "session.share.action.view": "보기", + "session.share.copy.copied": "복사됨", + "session.share.copy.copyLink": "링크 복사", + + "lsp.tooltip.none": "LSP 서버 없음", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "프롬프트 로드 중...", + "terminal.loading": "터미널 로드 중...", + "terminal.title": "터미널", + "terminal.title.numbered": "터미널 {{number}}", + "terminal.close": "터미널 닫기", + + "common.closeTab": "탭 닫기", + "common.dismiss": "닫기", + "common.requestFailed": "요청 실패", + "common.moreOptions": "더 많은 옵션", + "common.learnMore": "더 알아보기", + "common.rename": "이름 바꾸기", + "common.reset": "초기화", + "common.archive": "보관", + "common.delete": "삭제", + "common.close": "닫기", + "common.edit": "편집", + "common.loadMore": "더 불러오기", + + "sidebar.nav.projectsAndSessions": "프로젝트 및 세션", + "sidebar.settings": "설정", + "sidebar.help": "도움말", + "sidebar.workspaces.enable": "작업 공간 활성화", + "sidebar.workspaces.disable": "작업 공간 비활성화", + "sidebar.gettingStarted.title": "시작하기", + "sidebar.gettingStarted.line1": "OpenCode에는 무료 모델이 포함되어 있어 즉시 시작할 수 있습니다.", + "sidebar.gettingStarted.line2": "Claude, GPT, Gemini 등을 포함한 모델을 사용하려면 공급자를 연결하세요.", + "sidebar.project.recentSessions": "최근 세션", + "sidebar.project.viewAllSessions": "모든 세션 보기", + + "settings.section.desktop": "데스크톱", + "settings.tab.general": "일반", + "settings.tab.shortcuts": "단축키", + + "settings.general.section.appearance": "모양", + "settings.general.section.notifications": "시스템 알림", + "settings.general.section.sounds": "효과음", + + "settings.general.row.language.title": "언어", + "settings.general.row.language.description": "OpenCode 표시 언어 변경", + "settings.general.row.appearance.title": "모양", + "settings.general.row.appearance.description": "기기에서 OpenCode가 보이는 방식 사용자 지정", + "settings.general.row.theme.title": "테마", + "settings.general.row.theme.description": "OpenCode 테마 사용자 지정", + "settings.general.row.font.title": "글꼴", + "settings.general.row.font.description": "코드 블록에 사용되는 고정폭 글꼴 사용자 지정", + + "settings.general.notifications.agent.title": "에이전트", + "settings.general.notifications.agent.description": "에이전트가 완료되거나 주의가 필요할 때 시스템 알림 표시", + "settings.general.notifications.permissions.title": "권한", + "settings.general.notifications.permissions.description": "권한이 필요할 때 시스템 알림 표시", + "settings.general.notifications.errors.title": "오류", + "settings.general.notifications.errors.description": "오류가 발생했을 때 시스템 알림 표시", + + "settings.general.sounds.agent.title": "에이전트", + "settings.general.sounds.agent.description": "에이전트가 완료되거나 주의가 필요할 때 소리 재생", + "settings.general.sounds.permissions.title": "권한", + "settings.general.sounds.permissions.description": "권한이 필요할 때 소리 재생", + "settings.general.sounds.errors.title": "오류", + "settings.general.sounds.errors.description": "오류가 발생했을 때 소리 재생", + + "settings.shortcuts.title": "키보드 단축키", + "settings.shortcuts.reset.button": "기본값으로 초기화", + "settings.shortcuts.reset.toast.title": "단축키 초기화됨", + "settings.shortcuts.reset.toast.description": "키보드 단축키가 기본값으로 초기화되었습니다.", + "settings.shortcuts.conflict.title": "단축키가 이미 사용 중임", + "settings.shortcuts.conflict.description": "{{keybind}}은(는) 이미 {{titles}}에 할당되어 있습니다.", + "settings.shortcuts.unassigned": "할당되지 않음", + "settings.shortcuts.pressKeys": "키 누르기", + "settings.shortcuts.search.placeholder": "단축키 검색", + "settings.shortcuts.search.empty": "단축키를 찾을 수 없습니다", + + "settings.shortcuts.group.general": "일반", + "settings.shortcuts.group.session": "세션", + "settings.shortcuts.group.navigation": "탐색", + "settings.shortcuts.group.modelAndAgent": "모델 및 에이전트", + "settings.shortcuts.group.terminal": "터미널", + "settings.shortcuts.group.prompt": "프롬프트", + + "settings.providers.title": "공급자", + "settings.providers.description": "공급자 설정은 여기서 구성할 수 있습니다.", + "settings.models.title": "모델", + "settings.models.description": "모델 설정은 여기서 구성할 수 있습니다.", + "settings.agents.title": "에이전트", + "settings.agents.description": "에이전트 설정은 여기서 구성할 수 있습니다.", + "settings.commands.title": "명령어", + "settings.commands.description": "명령어 설정은 여기서 구성할 수 있습니다.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP 설정은 여기서 구성할 수 있습니다.", + + "settings.permissions.title": "권한", + "settings.permissions.description": "서버가 기본적으로 사용할 수 있는 도구를 제어합니다.", + "settings.permissions.section.tools": "도구", + "settings.permissions.toast.updateFailed.title": "권한 업데이트 실패", + + "settings.permissions.action.allow": "허용", + "settings.permissions.action.ask": "묻기", + "settings.permissions.action.deny": "거부", + + "settings.permissions.tool.read.title": "읽기", + "settings.permissions.tool.read.description": "파일 읽기 (파일 경로와 일치)", + "settings.permissions.tool.edit.title": "편집", + "settings.permissions.tool.edit.description": "파일 수정 (편집, 쓰기, 패치 및 다중 편집 포함)", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "glob 패턴을 사용하여 파일 일치", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "정규식을 사용하여 파일 내용 검색", + "settings.permissions.tool.list.title": "목록", + "settings.permissions.tool.list.description": "디렉터리 내 파일 나열", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "셸 명령어 실행", + "settings.permissions.tool.task.title": "작업", + "settings.permissions.tool.task.description": "하위 에이전트 실행", + "settings.permissions.tool.skill.title": "기술", + "settings.permissions.tool.skill.description": "이름으로 기술 로드", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "언어 서버 쿼리 실행", + "settings.permissions.tool.todoread.title": "할 일 읽기", + "settings.permissions.tool.todoread.description": "할 일 목록 읽기", + "settings.permissions.tool.todowrite.title": "할 일 쓰기", + "settings.permissions.tool.todowrite.description": "할 일 목록 업데이트", + "settings.permissions.tool.webfetch.title": "웹 가져오기", + "settings.permissions.tool.webfetch.description": "URL에서 콘텐츠 가져오기", + "settings.permissions.tool.websearch.title": "웹 검색", + "settings.permissions.tool.websearch.description": "웹 검색", + "settings.permissions.tool.codesearch.title": "코드 검색", + "settings.permissions.tool.codesearch.description": "웹에서 코드 검색", + "settings.permissions.tool.external_directory.title": "외부 디렉터리", + "settings.permissions.tool.external_directory.description": "프로젝트 디렉터리 외부의 파일에 액세스", + "settings.permissions.tool.doom_loop.title": "무한 반복", + "settings.permissions.tool.doom_loop.description": "동일한 입력으로 반복되는 도구 호출 감지", + + "session.delete.failed.title": "세션 삭제 실패", + "session.delete.title": "세션 삭제", + "session.delete.confirm": '"{{name}}" 세션을 삭제하시겠습니까?', + "session.delete.button": "세션 삭제", + + "workspace.new": "새 작업 공간", + "workspace.type.local": "로컬", + "workspace.type.sandbox": "샌드박스", + "workspace.create.failed.title": "작업 공간 생성 실패", + "workspace.delete.failed.title": "작업 공간 삭제 실패", + "workspace.resetting.title": "작업 공간 재설정 중", + "workspace.resetting.description": "잠시 시간이 걸릴 수 있습니다.", + "workspace.reset.failed.title": "작업 공간 재설정 실패", + "workspace.reset.success.title": "작업 공간 재설정됨", + "workspace.reset.success.description": "작업 공간이 이제 기본 브랜치와 일치합니다.", + "workspace.status.checking": "병합되지 않은 변경 사항 확인 중...", + "workspace.status.error": "Git 상태를 확인할 수 없습니다.", + "workspace.status.clean": "병합되지 않은 변경 사항이 감지되지 않았습니다.", + "workspace.status.dirty": "이 작업 공간에서 병합되지 않은 변경 사항이 감지되었습니다.", + "workspace.delete.title": "작업 공간 삭제", + "workspace.delete.confirm": '"{{name}}" 작업 공간을 삭제하시겠습니까?', + "workspace.delete.button": "작업 공간 삭제", + "workspace.reset.title": "작업 공간 재설정", + "workspace.reset.confirm": '"{{name}}" 작업 공간을 재설정하시겠습니까?', + "workspace.reset.button": "작업 공간 재설정", + "workspace.reset.archived.none": "활성 세션이 보관되지 않습니다.", + "workspace.reset.archived.one": "1개의 세션이 보관됩니다.", + "workspace.reset.archived.many": "{{count}}개의 세션이 보관됩니다.", + "workspace.reset.note": "이 작업은 작업 공간을 기본 브랜치와 일치하도록 재설정합니다.", +} diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts new file mode 100644 index 00000000000..5a82ec1e04b --- /dev/null +++ b/packages/app/src/i18n/no.ts @@ -0,0 +1,600 @@ +import { dict as en } from "./en" +type Keys = keyof typeof en + +export const dict = { + "command.category.suggested": "Foreslått", + "command.category.view": "Visning", + "command.category.project": "Prosjekt", + "command.category.provider": "Leverandør", + "command.category.server": "Server", + "command.category.session": "Sesjon", + "command.category.theme": "Tema", + "command.category.language": "Språk", + "command.category.file": "Fil", + "command.category.terminal": "Terminal", + "command.category.model": "Modell", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Tillatelser", + "command.category.workspace": "Arbeidsområde", + "command.category.settings": "Innstillinger", + + "theme.scheme.system": "System", + "theme.scheme.light": "Lys", + "theme.scheme.dark": "Mørk", + + "command.sidebar.toggle": "Veksle sidepanel", + "command.project.open": "Åpne prosjekt", + "command.provider.connect": "Koble til leverandør", + "command.server.switch": "Bytt server", + "command.settings.open": "Åpne innstillinger", + "command.session.previous": "Forrige sesjon", + "command.session.next": "Neste sesjon", + "command.session.archive": "Arkiver sesjon", + + "command.palette": "Kommandopalett", + + "command.theme.cycle": "Bytt tema", + "command.theme.set": "Bruk tema: {{theme}}", + "command.theme.scheme.cycle": "Bytt fargevalg", + "command.theme.scheme.set": "Bruk fargevalg: {{scheme}}", + + "command.language.cycle": "Bytt språk", + "command.language.set": "Bruk språk: {{language}}", + + "command.session.new": "Ny sesjon", + "command.file.open": "Åpne fil", + "command.file.open.description": "Søk i filer og kommandoer", + "command.terminal.toggle": "Veksle terminal", + "command.review.toggle": "Veksle gjennomgang", + "command.terminal.new": "Ny terminal", + "command.terminal.new.description": "Opprett en ny terminalfane", + "command.steps.toggle": "Veksle trinn", + "command.steps.toggle.description": "Vis eller skjul trinn for gjeldende melding", + "command.message.previous": "Forrige melding", + "command.message.previous.description": "Gå til forrige brukermelding", + "command.message.next": "Neste melding", + "command.message.next.description": "Gå til neste brukermelding", + "command.model.choose": "Velg modell", + "command.model.choose.description": "Velg en annen modell", + "command.mcp.toggle": "Veksle MCP-er", + "command.mcp.toggle.description": "Veksle MCP-er", + "command.agent.cycle": "Bytt agent", + "command.agent.cycle.description": "Bytt til neste agent", + "command.agent.cycle.reverse": "Bytt agent bakover", + "command.agent.cycle.reverse.description": "Bytt til forrige agent", + "command.model.variant.cycle": "Bytt tenkeinnsats", + "command.model.variant.cycle.description": "Bytt til neste innsatsnivå", + "command.permissions.autoaccept.enable": "Godta endringer automatisk", + "command.permissions.autoaccept.disable": "Slutt å godta endringer automatisk", + "command.session.undo": "Angre", + "command.session.undo.description": "Angre siste melding", + "command.session.redo": "Gjør om", + "command.session.redo.description": "Gjør om siste angrede melding", + "command.session.compact": "Komprimer sesjon", + "command.session.compact.description": "Oppsummer sesjonen for å redusere kontekststørrelsen", + "command.session.fork": "Forgren fra melding", + "command.session.fork.description": "Opprett en ny sesjon fra en tidligere melding", + "command.session.share": "Del sesjon", + "command.session.share.description": "Del denne sesjonen og kopier URL-en til utklippstavlen", + "command.session.unshare": "Slutt å dele sesjon", + "command.session.unshare.description": "Slutt å dele denne sesjonen", + + "palette.search.placeholder": "Søk i filer og kommandoer", + "palette.empty": "Ingen resultater funnet", + "palette.group.commands": "Kommandoer", + "palette.group.files": "Filer", + + "dialog.provider.search.placeholder": "Søk etter leverandører", + "dialog.provider.empty": "Ingen leverandører funnet", + "dialog.provider.group.popular": "Populære", + "dialog.provider.group.other": "Andre", + "dialog.provider.tag.recommended": "Anbefalt", + "dialog.provider.anthropic.note": "Koble til med Claude Pro/Max eller API-nøkkel", + + "dialog.model.select.title": "Velg modell", + "dialog.model.search.placeholder": "Søk etter modeller", + "dialog.model.empty": "Ingen modellresultater", + "dialog.model.manage": "Administrer modeller", + "dialog.model.manage.description": "Tilpass hvilke modeller som vises i modellvelgeren.", + + "dialog.model.unpaid.freeModels.title": "Gratis modeller levert av OpenCode", + "dialog.model.unpaid.addMore.title": "Legg til flere modeller fra populære leverandører", + + "dialog.provider.viewAll": "Vis alle leverandører", + + "provider.connect.title": "Koble til {{provider}}", + "provider.connect.title.anthropicProMax": "Logg inn med Claude Pro/Max", + "provider.connect.selectMethod": "Velg innloggingsmetode for {{provider}}.", + "provider.connect.method.apiKey": "API-nøkkel", + "provider.connect.status.inProgress": "Autorisering pågår...", + "provider.connect.status.waiting": "Venter på autorisering...", + "provider.connect.status.failed": "Autorisering mislyktes: {{error}}", + "provider.connect.apiKey.description": + "Skriv inn din {{provider}} API-nøkkel for å koble til kontoen din og bruke {{provider}}-modeller i OpenCode.", + "provider.connect.apiKey.label": "{{provider}} API-nøkkel", + "provider.connect.apiKey.placeholder": "API-nøkkel", + "provider.connect.apiKey.required": "API-nøkkel er påkrevd", + "provider.connect.opencodeZen.line1": + "OpenCode Zen gir deg tilgang til et utvalg av pålitelige optimaliserte modeller for kodeagenter.", + "provider.connect.opencodeZen.line2": + "Med én enkelt API-nøkkel får du tilgang til modeller som Claude, GPT, Gemini, GLM og flere.", + "provider.connect.opencodeZen.visit.prefix": "Besøk ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " for å hente API-nøkkelen din.", + "provider.connect.oauth.code.visit.prefix": "Besøk ", + "provider.connect.oauth.code.visit.link": "denne lenken", + "provider.connect.oauth.code.visit.suffix": + " for å hente autorisasjonskoden din for å koble til kontoen din og bruke {{provider}}-modeller i OpenCode.", + "provider.connect.oauth.code.label": "{{method}} autorisasjonskode", + "provider.connect.oauth.code.placeholder": "Autorisasjonskode", + "provider.connect.oauth.code.required": "Autorisasjonskode er påkrevd", + "provider.connect.oauth.code.invalid": "Ugyldig autorisasjonskode", + "provider.connect.oauth.auto.visit.prefix": "Besøk ", + "provider.connect.oauth.auto.visit.link": "denne lenken", + "provider.connect.oauth.auto.visit.suffix": + " og skriv inn koden nedenfor for å koble til kontoen din og bruke {{provider}}-modeller i OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Bekreftelseskode", + "provider.connect.toast.connected.title": "{{provider}} tilkoblet", + "provider.connect.toast.connected.description": "{{provider}}-modeller er nå tilgjengelige.", + + "model.tag.free": "Gratis", + "model.tag.latest": "Nyeste", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "tekst", + "model.input.image": "bilde", + "model.input.audio": "lyd", + "model.input.video": "video", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Tillater: {{inputs}}", + "model.tooltip.reasoning.allowed": "Tillater resonnering", + "model.tooltip.reasoning.none": "Ingen resonnering", + "model.tooltip.context": "Kontekstgrense {{limit}}", + + "common.search.placeholder": "Søk", + "common.goBack": "Gå tilbake", + "common.loading": "Laster", + "common.loading.ellipsis": "...", + "common.cancel": "Avbryt", + "common.submit": "Send inn", + "common.save": "Lagre", + "common.saving": "Lagrer...", + "common.default": "Standard", + "common.attachment": "vedlegg", + + "prompt.placeholder.shell": "Skriv inn shell-kommando...", + "prompt.placeholder.normal": 'Spør om hva som helst... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "ESC for å avslutte", + + "prompt.example.1": "Fiks en TODO i kodebasen", + "prompt.example.2": "Hva er teknologistabelen i dette prosjektet?", + "prompt.example.3": "Fiks ødelagte tester", + "prompt.example.4": "Forklar hvordan autentisering fungerer", + "prompt.example.5": "Finn og fiks sikkerhetssårbarheter", + "prompt.example.6": "Legg til enhetstester for brukerservicen", + "prompt.example.7": "Refaktorer denne funksjonen for bedre lesbarhet", + "prompt.example.8": "Hva betyr denne feilen?", + "prompt.example.9": "Hjelp meg med å feilsøke dette problemet", + "prompt.example.10": "Generer API-dokumentasjon", + "prompt.example.11": "Optimaliser databasespørringer", + "prompt.example.12": "Legg til inputvalidering", + "prompt.example.13": "Lag en ny komponent for...", + "prompt.example.14": "Hvordan deployer jeg dette prosjektet?", + "prompt.example.15": "Gjennomgå koden min for beste praksis", + "prompt.example.16": "Legg til feilhåndtering i denne funksjonen", + "prompt.example.17": "Forklar dette regex-mønsteret", + "prompt.example.18": "Konverter dette til TypeScript", + "prompt.example.19": "Legg til logging i hele kodebasen", + "prompt.example.20": "Hvilke avhengigheter er utdaterte?", + "prompt.example.21": "Hjelp meg med å skrive et migreringsskript", + "prompt.example.22": "Implementer caching for dette endepunktet", + "prompt.example.23": "Legg til paginering i denne listen", + "prompt.example.24": "Lag en CLI-kommando for...", + "prompt.example.25": "Hvordan fungerer miljøvariabler her?", + + "prompt.popover.emptyResults": "Ingen matchende resultater", + "prompt.popover.emptyCommands": "Ingen matchende kommandoer", + "prompt.dropzone.label": "Slipp bilder eller PDF-er her", + "prompt.slash.badge.custom": "egendefinert", + "prompt.context.active": "aktiv", + "prompt.context.includeActiveFile": "Inkluder aktiv fil", + "prompt.context.removeActiveFile": "Fjern aktiv fil fra kontekst", + "prompt.context.removeFile": "Fjern fil fra kontekst", + "prompt.action.attachFile": "Legg ved fil", + "prompt.attachment.remove": "Fjern vedlegg", + "prompt.action.send": "Send", + "prompt.action.stop": "Stopp", + + "prompt.toast.pasteUnsupported.title": "Liming ikke støttet", + "prompt.toast.pasteUnsupported.description": "Kun bilder eller PDF-er kan limes inn her.", + "prompt.toast.modelAgentRequired.title": "Velg en agent og modell", + "prompt.toast.modelAgentRequired.description": "Velg en agent og modell før du sender en forespørsel.", + "prompt.toast.worktreeCreateFailed.title": "Kunne ikke opprette worktree", + "prompt.toast.sessionCreateFailed.title": "Kunne ikke opprette sesjon", + "prompt.toast.shellSendFailed.title": "Kunne ikke sende shell-kommando", + "prompt.toast.commandSendFailed.title": "Kunne ikke sende kommando", + "prompt.toast.promptSendFailed.title": "Kunne ikke sende forespørsel", + + "dialog.mcp.title": "MCP-er", + "dialog.mcp.description": "{{enabled}} av {{total}} aktivert", + "dialog.mcp.empty": "Ingen MCP-er konfigurert", + + "mcp.status.connected": "tilkoblet", + "mcp.status.failed": "mislyktes", + "mcp.status.needs_auth": "trenger autentisering", + "mcp.status.disabled": "deaktivert", + + "dialog.fork.empty": "Ingen meldinger å forgrene fra", + + "dialog.directory.search.placeholder": "Søk etter mapper", + "dialog.directory.empty": "Ingen mapper funnet", + + "dialog.server.title": "Servere", + "dialog.server.description": "Bytt hvilken OpenCode-server denne appen kobler til.", + "dialog.server.search.placeholder": "Søk etter servere", + "dialog.server.empty": "Ingen servere ennå", + "dialog.server.add.title": "Legg til en server", + "dialog.server.add.url": "Server-URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Kunne ikke koble til server", + "dialog.server.add.checking": "Sjekker...", + "dialog.server.add.button": "Legg til", + "dialog.server.default.title": "Standardserver", + "dialog.server.default.description": + "Koble til denne serveren ved oppstart i stedet for å starte en lokal server. Krever omstart.", + "dialog.server.default.none": "Ingen server valgt", + "dialog.server.default.set": "Sett gjeldende server som standard", + "dialog.server.default.clear": "Tøm", + "dialog.server.action.remove": "Fjern server", + + "dialog.project.edit.title": "Rediger prosjekt", + "dialog.project.edit.name": "Navn", + "dialog.project.edit.icon": "Ikon", + "dialog.project.edit.icon.alt": "Prosjektikon", + "dialog.project.edit.icon.hint": "Klikk eller dra et bilde", + "dialog.project.edit.icon.recommended": "Anbefalt: 128x128px", + "dialog.project.edit.color": "Farge", + "dialog.project.edit.color.select": "Velg fargen {{color}}", + + "context.breakdown.title": "Kontekstfordeling", + "context.breakdown.note": 'Omtrentlig fordeling av input-tokens. "Annet" inkluderer verktøydefinisjoner og overhead.', + "context.breakdown.system": "System", + "context.breakdown.user": "Bruker", + "context.breakdown.assistant": "Assistent", + "context.breakdown.tool": "Verktøykall", + "context.breakdown.other": "Annet", + + "context.systemPrompt.title": "Systemprompt", + "context.rawMessages.title": "Rå meldinger", + + "context.stats.session": "Sesjon", + "context.stats.messages": "Meldinger", + "context.stats.provider": "Leverandør", + "context.stats.model": "Modell", + "context.stats.limit": "Kontekstgrense", + "context.stats.totalTokens": "Totalt antall tokens", + "context.stats.usage": "Forbruk", + "context.stats.inputTokens": "Input-tokens", + "context.stats.outputTokens": "Output-tokens", + "context.stats.reasoningTokens": "Resonnerings-tokens", + "context.stats.cacheTokens": "Cache-tokens (les/skriv)", + "context.stats.userMessages": "Brukermeldinger", + "context.stats.assistantMessages": "Assistentmeldinger", + "context.stats.totalCost": "Total kostnad", + "context.stats.sessionCreated": "Sesjon opprettet", + "context.stats.lastActivity": "Siste aktivitet", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Forbruk", + "context.usage.cost": "Kostnad", + "context.usage.clickToView": "Klikk for å se kontekst", + "context.usage.view": "Se kontekstforbruk", + + "language.en": "Engelsk", + "language.zh": "Kinesisk (forenklet)", + "language.zht": "Kinesisk (tradisjonell)", + "language.ko": "Koreansk", + "language.de": "Tysk", + "language.es": "Spansk", + "language.fr": "Fransk", + "language.ja": "Japansk", + "language.da": "Dansk", + "language.ru": "Russisk", + "language.pl": "Polsk", + "language.ar": "Arabisk", + "language.no": "Norsk", + "language.br": "Portugisisk (Brasil)", + + "toast.language.title": "Språk", + "toast.language.description": "Byttet til {{language}}", + + "toast.theme.title": "Tema byttet", + "toast.scheme.title": "Fargevalg", + + "toast.permissions.autoaccept.on.title": "Godtar endringer automatisk", + "toast.permissions.autoaccept.on.description": "Redigerings- og skrivetillatelser vil bli godkjent automatisk", + "toast.permissions.autoaccept.off.title": "Sluttet å godta endringer automatisk", + "toast.permissions.autoaccept.off.description": "Redigerings- og skrivetillatelser vil kreve godkjenning", + + "toast.model.none.title": "Ingen modell valgt", + "toast.model.none.description": "Koble til en leverandør for å oppsummere denne sesjonen", + + "toast.file.loadFailed.title": "Kunne ikke laste fil", + + "toast.session.share.copyFailed.title": "Kunne ikke kopiere URL til utklippstavlen", + "toast.session.share.success.title": "Sesjon delt", + "toast.session.share.success.description": "Delings-URL kopiert til utklippstavlen!", + "toast.session.share.failed.title": "Kunne ikke dele sesjon", + "toast.session.share.failed.description": "Det oppstod en feil under deling av sesjonen", + + "toast.session.unshare.success.title": "Deling av sesjon stoppet", + "toast.session.unshare.success.description": "Sesjonen deles ikke lenger!", + "toast.session.unshare.failed.title": "Kunne ikke stoppe deling av sesjon", + "toast.session.unshare.failed.description": "Det oppstod en feil da delingen av sesjonen skulle stoppes", + + "toast.session.listFailed.title": "Kunne ikke laste sesjoner for {{project}}", + + "toast.update.title": "Oppdatering tilgjengelig", + "toast.update.description": "En ny versjon av OpenCode ({{version}}) er nå tilgjengelig for installasjon.", + "toast.update.action.installRestart": "Installer og start på nytt", + "toast.update.action.notYet": "Ikke nå", + + "error.page.title": "Noe gikk galt", + "error.page.description": "Det oppstod en feil under lasting av applikasjonen.", + "error.page.details.label": "Feildetaljer", + "error.page.action.restart": "Start på nytt", + "error.page.action.checking": "Sjekker...", + "error.page.action.checkUpdates": "Se etter oppdateringer", + "error.page.action.updateTo": "Oppdater til {{version}}", + "error.page.report.prefix": "Vennligst rapporter denne feilen til OpenCode-teamet", + "error.page.report.discord": "på Discord", + "error.page.version": "Versjon: {{version}}", + + "error.dev.rootNotFound": + "Rotelement ikke funnet. Glemte du å legge det til i index.html? Eller kanskje id-attributten er feilstavet?", + + "error.globalSync.connectFailed": "Kunne ikke koble til server. Kjører det en server på `{{url}}`?", + + "error.chain.unknown": "Ukjent feil", + "error.chain.causedBy": "Forårsaket av:", + "error.chain.apiError": "API-feil", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Kan prøves på nytt: {{retryable}}", + "error.chain.responseBody": "Responsinnhold:\n{{body}}", + "error.chain.didYouMean": "Mente du: {{suggestions}}", + "error.chain.modelNotFound": "Modell ikke funnet: {{provider}}/{{model}}", + "error.chain.checkConfig": "Sjekk leverandør-/modellnavnene i konfigurasjonen din (opencode.json)", + "error.chain.mcpFailed": 'MCP-server "{{name}}" mislyktes. Merk at OpenCode ikke støtter MCP-autentisering ennå.', + "error.chain.providerAuthFailed": "Leverandørautentisering mislyktes ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Kunne ikke initialisere leverandør "{{provider}}". Sjekk legitimasjon og konfigurasjon.', + "error.chain.configJsonInvalid": "Konfigurasjonsfilen på {{path}} er ikke gyldig JSON(C)", + "error.chain.configJsonInvalidWithMessage": "Konfigurasjonsfilen på {{path}} er ikke gyldig JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Mappen "{{dir}}" i {{path}} er ikke gyldig. Gi mappen nytt navn til "{{suggestion}}" eller fjern den. Dette er en vanlig skrivefeil.', + "error.chain.configFrontmatterError": "Kunne ikke analysere frontmatter i {{path}}:\n{{message}}", + "error.chain.configInvalid": "Konfigurasjonsfilen på {{path}} er ugyldig", + "error.chain.configInvalidWithMessage": "Konfigurasjonsfilen på {{path}} er ugyldig: {{message}}", + + "notification.permission.title": "Tillatelse påkrevd", + "notification.permission.description": "{{sessionTitle}} i {{projectName}} trenger tillatelse", + "notification.question.title": "Spørsmål", + "notification.question.description": "{{sessionTitle}} i {{projectName}} har et spørsmål", + "notification.action.goToSession": "Gå til sesjon", + + "notification.session.responseReady.title": "Svar klart", + "notification.session.error.title": "Sesjonsfeil", + "notification.session.error.fallbackDescription": "Det oppstod en feil", + + "home.recentProjects": "Nylige prosjekter", + "home.empty.title": "Ingen nylige prosjekter", + "home.empty.description": "Kom i gang ved å åpne et lokalt prosjekt", + + "session.tab.session": "Sesjon", + "session.tab.review": "Gjennomgang", + "session.tab.context": "Kontekst", + "session.panel.reviewAndFiles": "Gjennomgang og filer", + "session.review.filesChanged": "{{count}} filer endret", + "session.review.loadingChanges": "Laster endringer...", + "session.review.empty": "Ingen endringer i denne sesjonen ennå", + "session.messages.renderEarlier": "Vis tidligere meldinger", + "session.messages.loadingEarlier": "Laster inn tidligere meldinger...", + "session.messages.loadEarlier": "Last inn tidligere meldinger", + "session.messages.loading": "Laster meldinger...", + "session.messages.jumpToLatest": "Hopp til nyeste", + + "session.context.addToContext": "Legg til {{selection}} i kontekst", + + "session.new.worktree.main": "Hovedgren", + "session.new.worktree.mainWithBranch": "Hovedgren ({{branch}})", + "session.new.worktree.create": "Opprett nytt worktree", + "session.new.lastModified": "Sist endret", + + "session.header.search.placeholder": "Søk i {{project}}", + "session.header.searchFiles": "Søk etter filer", + + "session.share.popover.title": "Publiser på nett", + "session.share.popover.description.shared": + "Denne sesjonen er offentlig på nettet. Den er tilgjengelig for alle med lenken.", + "session.share.popover.description.unshared": + "Del sesjonen offentlig på nettet. Den vil være tilgjengelig for alle med lenken.", + "session.share.action.share": "Del", + "session.share.action.publish": "Publiser", + "session.share.action.publishing": "Publiserer...", + "session.share.action.unpublish": "Avpubliser", + "session.share.action.unpublishing": "Avpubliserer...", + "session.share.action.view": "Vis", + "session.share.copy.copied": "Kopiert", + "session.share.copy.copyLink": "Kopier lenke", + + "lsp.tooltip.none": "Ingen LSP-servere", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Laster prompt...", + "terminal.loading": "Laster terminal...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Lukk terminal", + "terminal.connectionLost.title": "Tilkobling mistet", + "terminal.connectionLost.description": + "Terminalforbindelsen ble avbrutt. Dette kan skje når serveren starter på nytt.", + + "common.closeTab": "Lukk fane", + "common.dismiss": "Avvis", + "common.requestFailed": "Forespørsel mislyktes", + "common.moreOptions": "Flere alternativer", + "common.learnMore": "Lær mer", + "common.rename": "Gi nytt navn", + "common.reset": "Tilbakestill", + "common.delete": "Slett", + "common.close": "Lukk", + "common.edit": "Rediger", + "common.loadMore": "Last flere", + "common.key.esc": "ESC", + + "sidebar.menu.toggle": "Veksle meny", + "sidebar.nav.projectsAndSessions": "Prosjekter og sesjoner", + "sidebar.settings": "Innstillinger", + "sidebar.help": "Hjelp", + "sidebar.workspaces.enable": "Aktiver arbeidsområder", + "sidebar.workspaces.disable": "Deaktiver arbeidsområder", + "sidebar.gettingStarted.title": "Kom i gang", + "sidebar.gettingStarted.line1": "OpenCode inkluderer gratis modeller så du kan starte umiddelbart.", + "sidebar.gettingStarted.line2": "Koble til en leverandør for å bruke modeller, inkl. Claude, GPT, Gemini osv.", + "sidebar.project.recentSessions": "Nylige sesjoner", + "sidebar.project.viewAllSessions": "Vis alle sesjoner", + + "settings.section.desktop": "Skrivebord", + "settings.tab.general": "Generelt", + "settings.tab.shortcuts": "Snarveier", + + "settings.general.section.appearance": "Utseende", + "settings.general.section.notifications": "Systemvarsler", + "settings.general.section.sounds": "Lydeffekter", + + "settings.general.row.language.title": "Språk", + "settings.general.row.language.description": "Endre visningsspråket for OpenCode", + "settings.general.row.appearance.title": "Utseende", + "settings.general.row.appearance.description": "Tilpass hvordan OpenCode ser ut på enheten din", + "settings.general.row.theme.title": "Tema", + "settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.", + "settings.general.row.font.title": "Skrift", + "settings.general.row.font.description": "Tilpass mono-skriften som brukes i kodeblokker", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Vis systemvarsel når agenten er ferdig eller trenger oppmerksomhet", + "settings.general.notifications.permissions.title": "Tillatelser", + "settings.general.notifications.permissions.description": "Vis systemvarsel når en tillatelse er påkrevd", + "settings.general.notifications.errors.title": "Feil", + "settings.general.notifications.errors.description": "Vis systemvarsel når det oppstår en feil", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Spill av lyd når agenten er ferdig eller trenger oppmerksomhet", + "settings.general.sounds.permissions.title": "Tillatelser", + "settings.general.sounds.permissions.description": "Spill av lyd når en tillatelse er påkrevd", + "settings.general.sounds.errors.title": "Feil", + "settings.general.sounds.errors.description": "Spill av lyd når det oppstår en feil", + + "settings.shortcuts.title": "Tastatursnarveier", + "settings.shortcuts.reset.button": "Tilbakestill til standard", + "settings.shortcuts.reset.toast.title": "Snarveier tilbakestilt", + "settings.shortcuts.reset.toast.description": "Tastatursnarveier er tilbakestilt til standard.", + "settings.shortcuts.conflict.title": "Snarvei allerede i bruk", + "settings.shortcuts.conflict.description": "{{keybind}} er allerede tilordnet til {{titles}}.", + "settings.shortcuts.unassigned": "Ikke tilordnet", + "settings.shortcuts.pressKeys": "Trykk taster", + "settings.shortcuts.search.placeholder": "Søk etter snarveier", + "settings.shortcuts.search.empty": "Ingen snarveier funnet", + + "settings.shortcuts.group.general": "Generelt", + "settings.shortcuts.group.session": "Sesjon", + "settings.shortcuts.group.navigation": "Navigasjon", + "settings.shortcuts.group.modelAndAgent": "Modell og agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Leverandører", + "settings.providers.description": "Leverandørinnstillinger vil kunne konfigureres her.", + "settings.models.title": "Modeller", + "settings.models.description": "Modellinnstillinger vil kunne konfigureres her.", + "settings.agents.title": "Agenter", + "settings.agents.description": "Agentinnstillinger vil kunne konfigureres her.", + "settings.commands.title": "Kommandoer", + "settings.commands.description": "Kommandoinnstillinger vil kunne konfigureres her.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP-innstillinger vil kunne konfigureres her.", + + "settings.permissions.title": "Tillatelser", + "settings.permissions.description": "Kontroller hvilke verktøy serveren kan bruke som standard.", + "settings.permissions.section.tools": "Verktøy", + "settings.permissions.toast.updateFailed.title": "Kunne ikke oppdatere tillatelser", + + "settings.permissions.action.allow": "Tillat", + "settings.permissions.action.ask": "Spør", + "settings.permissions.action.deny": "Avslå", + + "settings.permissions.tool.read.title": "Les", + "settings.permissions.tool.read.description": "Lesing av en fil (matcher filbanen)", + "settings.permissions.tool.edit.title": "Rediger", + "settings.permissions.tool.edit.description": + "Endre filer, inkludert redigeringer, skriving, patcher og multi-redigeringer", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Match filer ved hjelp av glob-mønstre", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Søk i filinnhold ved hjelp av regulære uttrykk", + "settings.permissions.tool.list.title": "Liste", + "settings.permissions.tool.list.description": "List filer i en mappe", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Kjør shell-kommandoer", + "settings.permissions.tool.task.title": "Oppgave", + "settings.permissions.tool.task.description": "Start underagenter", + "settings.permissions.tool.skill.title": "Ferdighet", + "settings.permissions.tool.skill.description": "Last en ferdighet etter navn", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Kjør språkserverforespørsler", + "settings.permissions.tool.todoread.title": "Les gjøremål", + "settings.permissions.tool.todoread.description": "Les gjøremålslisten", + "settings.permissions.tool.todowrite.title": "Skriv gjøremål", + "settings.permissions.tool.todowrite.description": "Oppdater gjøremålslisten", + "settings.permissions.tool.webfetch.title": "Webhenting", + "settings.permissions.tool.webfetch.description": "Hent innhold fra en URL", + "settings.permissions.tool.websearch.title": "Websøk", + "settings.permissions.tool.websearch.description": "Søk på nettet", + "settings.permissions.tool.codesearch.title": "Kodesøk", + "settings.permissions.tool.codesearch.description": "Søk etter kode på nettet", + "settings.permissions.tool.external_directory.title": "Ekstern mappe", + "settings.permissions.tool.external_directory.description": "Få tilgang til filer utenfor prosjektmappen", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "Oppdager gjentatte verktøykall med identisk input", + + "workspace.new": "Nytt arbeidsområde", + "workspace.type.local": "lokal", + "workspace.type.sandbox": "sandkasse", + "workspace.create.failed.title": "Kunne ikke opprette arbeidsområde", + "workspace.delete.failed.title": "Kunne ikke slette arbeidsområde", + "workspace.resetting.title": "Tilbakestiller arbeidsområde", + "workspace.resetting.description": "Dette kan ta et minutt.", + "workspace.reset.failed.title": "Kunne ikke tilbakestille arbeidsområde", + "workspace.reset.success.title": "Arbeidsområde tilbakestilt", + "workspace.reset.success.description": "Arbeidsområdet samsvarer nå med standardgrenen.", + "workspace.status.checking": "Sjekker for ikke-sammenslåtte endringer...", + "workspace.status.error": "Kunne ikke bekrefte git-status.", + "workspace.status.clean": "Ingen ikke-sammenslåtte endringer oppdaget.", + "workspace.status.dirty": "Ikke-sammenslåtte endringer oppdaget i dette arbeidsområdet.", + "workspace.delete.title": "Slett arbeidsområde", + "workspace.delete.confirm": 'Slette arbeidsområdet "{{name}}"?', + "workspace.delete.button": "Slett arbeidsområde", + "workspace.reset.title": "Tilbakestill arbeidsområde", + "workspace.reset.confirm": 'Tilbakestille arbeidsområdet "{{name}}"?', + "workspace.reset.button": "Tilbakestill arbeidsområde", + "workspace.reset.archived.none": "Ingen aktive sesjoner vil bli arkivert.", + "workspace.reset.archived.one": "1 sesjon vil bli arkivert.", + "workspace.reset.archived.many": "{{count}} sesjoner vil bli arkivert.", + "workspace.reset.note": "Dette vil tilbakestille arbeidsområdet til å samsvare med standardgrenen.", +} satisfies Partial> diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts new file mode 100644 index 00000000000..9d95424dd60 --- /dev/null +++ b/packages/app/src/i18n/pl.ts @@ -0,0 +1,659 @@ +export const dict = { + "command.category.suggested": "Sugerowane", + "command.category.view": "Widok", + "command.category.project": "Projekt", + "command.category.provider": "Dostawca", + "command.category.server": "Serwer", + "command.category.session": "Sesja", + "command.category.theme": "Motyw", + "command.category.language": "Język", + "command.category.file": "Plik", + "command.category.terminal": "Terminal", + "command.category.model": "Model", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Uprawnienia", + "command.category.workspace": "Przestrzeń robocza", + "command.category.settings": "Ustawienia", + + "theme.scheme.system": "Systemowy", + "theme.scheme.light": "Jasny", + "theme.scheme.dark": "Ciemny", + + "command.sidebar.toggle": "Przełącz pasek boczny", + "command.project.open": "Otwórz projekt", + "command.provider.connect": "Połącz dostawcę", + "command.server.switch": "Przełącz serwer", + "command.settings.open": "Otwórz ustawienia", + "command.session.previous": "Poprzednia sesja", + "command.session.next": "Następna sesja", + "command.session.archive": "Zarchiwizuj sesję", + + "command.palette": "Paleta poleceń", + + "command.theme.cycle": "Przełącz motyw", + "command.theme.set": "Użyj motywu: {{theme}}", + "command.theme.scheme.cycle": "Przełącz schemat kolorów", + "command.theme.scheme.set": "Użyj schematu kolorów: {{scheme}}", + + "command.language.cycle": "Przełącz język", + "command.language.set": "Użyj języka: {{language}}", + + "command.session.new": "Nowa sesja", + "command.file.open": "Otwórz plik", + "command.file.open.description": "Szukaj plików i poleceń", + "command.terminal.toggle": "Przełącz terminal", + "command.review.toggle": "Przełącz przegląd", + "command.terminal.new": "Nowy terminal", + "command.terminal.new.description": "Utwórz nową kartę terminala", + "command.steps.toggle": "Przełącz kroki", + "command.steps.toggle.description": "Pokaż lub ukryj kroki dla bieżącej wiadomości", + "command.message.previous": "Poprzednia wiadomość", + "command.message.previous.description": "Przejdź do poprzedniej wiadomości użytkownika", + "command.message.next": "Następna wiadomość", + "command.message.next.description": "Przejdź do następnej wiadomości użytkownika", + "command.model.choose": "Wybierz model", + "command.model.choose.description": "Wybierz inny model", + "command.mcp.toggle": "Przełącz MCP", + "command.mcp.toggle.description": "Przełącz MCP", + "command.agent.cycle": "Przełącz agenta", + "command.agent.cycle.description": "Przełącz na następnego agenta", + "command.agent.cycle.reverse": "Przełącz agenta wstecz", + "command.agent.cycle.reverse.description": "Przełącz na poprzedniego agenta", + "command.model.variant.cycle": "Przełącz wysiłek myślowy", + "command.model.variant.cycle.description": "Przełącz na następny poziom wysiłku", + "command.permissions.autoaccept.enable": "Automatyczne akceptowanie edycji", + "command.permissions.autoaccept.disable": "Zatrzymaj automatyczne akceptowanie edycji", + "command.session.undo": "Cofnij", + "command.session.undo.description": "Cofnij ostatnią wiadomość", + "command.session.redo": "Ponów", + "command.session.redo.description": "Ponów ostatnią cofniętą wiadomość", + "command.session.compact": "Kompaktuj sesję", + "command.session.compact.description": "Podsumuj sesję, aby zmniejszyć rozmiar kontekstu", + "command.session.fork": "Rozwidlij od wiadomości", + "command.session.fork.description": "Utwórz nową sesję od poprzedniej wiadomości", + "command.session.share": "Udostępnij sesję", + "command.session.share.description": "Udostępnij tę sesję i skopiuj URL do schowka", + "command.session.unshare": "Przestań udostępniać sesję", + "command.session.unshare.description": "Zatrzymaj udostępnianie tej sesji", + + "palette.search.placeholder": "Szukaj plików i poleceń", + "palette.empty": "Brak wyników", + "palette.group.commands": "Polecenia", + "palette.group.files": "Pliki", + + "dialog.provider.search.placeholder": "Szukaj dostawców", + "dialog.provider.empty": "Nie znaleziono dostawców", + "dialog.provider.group.popular": "Popularne", + "dialog.provider.group.other": "Inne", + "dialog.provider.tag.recommended": "Zalecane", + "dialog.provider.anthropic.note": "Połącz z Claude Pro/Max lub kluczem API", + + "dialog.model.select.title": "Wybierz model", + "dialog.model.search.placeholder": "Szukaj modeli", + "dialog.model.empty": "Brak wyników modelu", + "dialog.model.manage": "Zarządzaj modelami", + "dialog.model.manage.description": "Dostosuj, które modele pojawiają się w wyborze modelu.", + + "dialog.model.unpaid.freeModels.title": "Darmowe modele dostarczane przez OpenCode", + "dialog.model.unpaid.addMore.title": "Dodaj więcej modeli od popularnych dostawców", + + "dialog.provider.viewAll": "Zobacz wszystkich dostawców", + + "provider.connect.title": "Połącz {{provider}}", + "provider.connect.title.anthropicProMax": "Zaloguj się z Claude Pro/Max", + "provider.connect.selectMethod": "Wybierz metodę logowania dla {{provider}}.", + "provider.connect.method.apiKey": "Klucz API", + "provider.connect.status.inProgress": "Autoryzacja w toku...", + "provider.connect.status.waiting": "Oczekiwanie na autoryzację...", + "provider.connect.status.failed": "Autoryzacja nie powiodła się: {{error}}", + "provider.connect.apiKey.description": + "Wprowadź swój klucz API {{provider}}, aby połączyć konto i używać modeli {{provider}} w OpenCode.", + "provider.connect.apiKey.label": "Klucz API {{provider}}", + "provider.connect.apiKey.placeholder": "Klucz API", + "provider.connect.apiKey.required": "Klucz API jest wymagany", + "provider.connect.opencodeZen.line1": + "OpenCode Zen daje dostęp do wybranego zestawu niezawodnych, zoptymalizowanych modeli dla agentów kodujących.", + "provider.connect.opencodeZen.line2": + "Z jednym kluczem API uzyskasz dostęp do modeli takich jak Claude, GPT, Gemini, GLM i więcej.", + "provider.connect.opencodeZen.visit.prefix": "Odwiedź ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": ", aby odebrać swój klucz API.", + "provider.connect.oauth.code.visit.prefix": "Odwiedź ", + "provider.connect.oauth.code.visit.link": "ten link", + "provider.connect.oauth.code.visit.suffix": + ", aby odebrać kod autoryzacyjny, połączyć konto i używać modeli {{provider}} w OpenCode.", + "provider.connect.oauth.code.label": "Kod autoryzacyjny {{method}}", + "provider.connect.oauth.code.placeholder": "Kod autoryzacyjny", + "provider.connect.oauth.code.required": "Kod autoryzacyjny jest wymagany", + "provider.connect.oauth.code.invalid": "Nieprawidłowy kod autoryzacyjny", + "provider.connect.oauth.auto.visit.prefix": "Odwiedź ", + "provider.connect.oauth.auto.visit.link": "ten link", + "provider.connect.oauth.auto.visit.suffix": + " i wprowadź poniższy kod, aby połączyć konto i używać modeli {{provider}} w OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Kod potwierdzający", + "provider.connect.toast.connected.title": "Połączono {{provider}}", + "provider.connect.toast.connected.description": "Modele {{provider}} są teraz dostępne do użycia.", + + "model.tag.free": "Darmowy", + "model.tag.latest": "Najnowszy", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "tekst", + "model.input.image": "obraz", + "model.input.audio": "audio", + "model.input.video": "wideo", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Obsługuje: {{inputs}}", + "model.tooltip.reasoning.allowed": "Obsługuje wnioskowanie", + "model.tooltip.reasoning.none": "Brak wnioskowania", + "model.tooltip.context": "Limit kontekstu {{limit}}", + + "common.search.placeholder": "Szukaj", + "common.goBack": "Wstecz", + "common.loading": "Ładowanie", + "common.loading.ellipsis": "...", + "common.cancel": "Anuluj", + "common.submit": "Prześlij", + "common.save": "Zapisz", + "common.saving": "Zapisywanie...", + "common.default": "Domyślny", + "common.attachment": "załącznik", + + "prompt.placeholder.shell": "Wpisz polecenie terminala...", + "prompt.placeholder.normal": 'Zapytaj o cokolwiek... "{{example}}"', + "prompt.mode.shell": "Terminal", + "prompt.mode.shell.exit": "esc aby wyjść", + + "prompt.example.1": "Napraw TODO w bazie kodu", + "prompt.example.2": "Jaki jest stos technologiczny tego projektu?", + "prompt.example.3": "Napraw zepsute testy", + "prompt.example.4": "Wyjaśnij jak działa uwierzytelnianie", + "prompt.example.5": "Znajdź i napraw luki w zabezpieczeniach", + "prompt.example.6": "Dodaj testy jednostkowe dla serwisu użytkownika", + "prompt.example.7": "Zrefaktoryzuj tę funkcję, aby była bardziej czytelna", + "prompt.example.8": "Co oznacza ten błąd?", + "prompt.example.9": "Pomóż mi zdebugować ten problem", + "prompt.example.10": "Wygeneruj dokumentację API", + "prompt.example.11": "Zoptymalizuj zapytania do bazy danych", + "prompt.example.12": "Dodaj walidację danych wejściowych", + "prompt.example.13": "Utwórz nowy komponent dla...", + "prompt.example.14": "Jak wdrożyć ten projekt?", + "prompt.example.15": "Sprawdź mój kod pod kątem najlepszych praktyk", + "prompt.example.16": "Dodaj obsługę błędów do tej funkcję", + "prompt.example.17": "Wyjaśnij ten wzorzec regex", + "prompt.example.18": "Przekonwertuj to na TypeScript", + "prompt.example.19": "Dodaj logowanie w całej bazie kodu", + "prompt.example.20": "Które zależności są przestarzałe?", + "prompt.example.21": "Pomóż mi napisać skrypt migracyjny", + "prompt.example.22": "Zaimplementuj cachowanie dla tego punktu końcowego", + "prompt.example.23": "Dodaj stronicowanie do tej listy", + "prompt.example.24": "Utwórz polecenie CLI dla...", + "prompt.example.25": "Jak działają tutaj zmienne środowiskowe?", + + "prompt.popover.emptyResults": "Brak pasujących wyników", + "prompt.popover.emptyCommands": "Brak pasujących poleceń", + "prompt.dropzone.label": "Upuść obrazy lub pliki PDF tutaj", + "prompt.slash.badge.custom": "własne", + "prompt.context.active": "aktywny", + "prompt.context.includeActiveFile": "Dołącz aktywny plik", + "prompt.context.removeActiveFile": "Usuń aktywny plik z kontekstu", + "prompt.context.removeFile": "Usuń plik z kontekstu", + "prompt.action.attachFile": "Załącz plik", + "prompt.attachment.remove": "Usuń załącznik", + "prompt.action.send": "Wyślij", + "prompt.action.stop": "Zatrzymaj", + + "prompt.toast.pasteUnsupported.title": "Nieobsługiwane wklejanie", + "prompt.toast.pasteUnsupported.description": "Tylko obrazy lub pliki PDF mogą być tutaj wklejane.", + "prompt.toast.modelAgentRequired.title": "Wybierz agenta i model", + "prompt.toast.modelAgentRequired.description": "Wybierz agenta i model przed wysłaniem zapytania.", + "prompt.toast.worktreeCreateFailed.title": "Nie udało się utworzyć drzewa roboczego", + "prompt.toast.sessionCreateFailed.title": "Nie udało się utworzyć sesji", + "prompt.toast.shellSendFailed.title": "Nie udało się wysłać polecenia powłoki", + "prompt.toast.commandSendFailed.title": "Nie udało się wysłać polecenia", + "prompt.toast.promptSendFailed.title": "Nie udało się wysłać zapytania", + + "dialog.mcp.title": "MCP", + "dialog.mcp.description": "{{enabled}} z {{total}} włączone", + "dialog.mcp.empty": "Brak skonfigurowanych MCP", + + "mcp.status.connected": "połączono", + "mcp.status.failed": "niepowodzenie", + "mcp.status.needs_auth": "wymaga autoryzacji", + "mcp.status.disabled": "wyłączone", + + "dialog.fork.empty": "Brak wiadomości do rozwidlenia", + + "dialog.directory.search.placeholder": "Szukaj folderów", + "dialog.directory.empty": "Nie znaleziono folderów", + + "dialog.server.title": "Serwery", + "dialog.server.description": "Przełącz serwer OpenCode, z którym łączy się ta aplikacja.", + "dialog.server.search.placeholder": "Szukaj serwerów", + "dialog.server.empty": "Brak serwerów", + "dialog.server.add.title": "Dodaj serwer", + "dialog.server.add.url": "URL serwera", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Nie można połączyć się z serwerem", + "dialog.server.add.checking": "Sprawdzanie...", + "dialog.server.add.button": "Dodaj", + "dialog.server.default.title": "Domyślny serwer", + "dialog.server.default.description": + "Połącz z tym serwerem przy uruchomieniu aplikacji zamiast uruchamiać lokalny serwer. Wymaga restartu.", + "dialog.server.default.none": "Nie wybrano serwera", + "dialog.server.default.set": "Ustaw bieżący serwer jako domyślny", + "dialog.server.default.clear": "Wyczyść", + "dialog.server.action.remove": "Usuń serwer", + + "dialog.project.edit.title": "Edytuj projekt", + "dialog.project.edit.name": "Nazwa", + "dialog.project.edit.icon": "Ikona", + "dialog.project.edit.icon.alt": "Ikona projektu", + "dialog.project.edit.icon.hint": "Kliknij lub przeciągnij obraz", + "dialog.project.edit.icon.recommended": "Zalecane: 128x128px", + "dialog.project.edit.color": "Kolor", + "dialog.project.edit.color.select": "Wybierz kolor {{color}}", + + "context.breakdown.title": "Podział kontekstu", + "context.breakdown.note": 'Przybliżony podział tokenów wejściowych. "Inne" obejmuje definicje narzędzi i narzut.', + "context.breakdown.system": "System", + "context.breakdown.user": "Użytkownik", + "context.breakdown.assistant": "Asystent", + "context.breakdown.tool": "Wywołania narzędzi", + "context.breakdown.other": "Inne", + + "context.systemPrompt.title": "Prompt systemowy", + "context.rawMessages.title": "Surowe wiadomości", + + "context.stats.session": "Sesja", + "context.stats.messages": "Wiadomości", + "context.stats.provider": "Dostawca", + "context.stats.model": "Model", + "context.stats.limit": "Limit kontekstu", + "context.stats.totalTokens": "Całkowita liczba tokenów", + "context.stats.usage": "Użycie", + "context.stats.inputTokens": "Tokeny wejściowe", + "context.stats.outputTokens": "Tokeny wyjściowe", + "context.stats.reasoningTokens": "Tokeny wnioskowania", + "context.stats.cacheTokens": "Tokeny pamięci podręcznej (odczyt/zapis)", + "context.stats.userMessages": "Wiadomości użytkownika", + "context.stats.assistantMessages": "Wiadomości asystenta", + "context.stats.totalCost": "Całkowity koszt", + "context.stats.sessionCreated": "Utworzono sesję", + "context.stats.lastActivity": "Ostatnia aktywność", + + "context.usage.tokens": "Tokeny", + "context.usage.usage": "Użycie", + "context.usage.cost": "Koszt", + "context.usage.clickToView": "Kliknij, aby zobaczyć kontekst", + "context.usage.view": "Pokaż użycie kontekstu", + + "language.en": "Angielski", + "language.zh": "Chiński", + "language.ko": "Koreański", + "language.de": "Niemiecki", + "language.es": "Hiszpański", + "language.fr": "Francuski", + "language.ja": "Japoński", + "language.da": "Duński", + "language.pl": "Polski", + "language.ru": "Rosyjski", + "language.ar": "Arabski", + "language.no": "Norweski", + "language.br": "Portugalski (Brazylia)", + + "toast.language.title": "Język", + "toast.language.description": "Przełączono na {{language}}", + + "toast.theme.title": "Przełączono motyw", + "toast.scheme.title": "Schemat kolorów", + + "toast.permissions.autoaccept.on.title": "Automatyczne akceptowanie edycji", + "toast.permissions.autoaccept.on.description": "Uprawnienia do edycji i zapisu będą automatycznie zatwierdzane", + "toast.permissions.autoaccept.off.title": "Zatrzymano automatyczne akceptowanie edycji", + "toast.permissions.autoaccept.off.description": "Uprawnienia do edycji i zapisu będą wymagały zatwierdzenia", + + "toast.model.none.title": "Nie wybrano modelu", + "toast.model.none.description": "Połącz dostawcę, aby podsumować tę sesję", + + "toast.file.loadFailed.title": "Nie udało się załadować pliku", + + "toast.session.share.copyFailed.title": "Nie udało się skopiować URL do schowka", + "toast.session.share.success.title": "Sesja udostępniona", + "toast.session.share.success.description": "Link udostępniania skopiowany do schowka!", + "toast.session.share.failed.title": "Nie udało się udostępnić sesji", + "toast.session.share.failed.description": "Wystąpił błąd podczas udostępniania sesji", + + "toast.session.unshare.success.title": "Zatrzymano udostępnianie sesji", + "toast.session.unshare.success.description": "Udostępnianie sesji zostało pomyślnie zatrzymane!", + "toast.session.unshare.failed.title": "Nie udało się zatrzymać udostępniania sesji", + "toast.session.unshare.failed.description": "Wystąpił błąd podczas zatrzymywania udostępniania sesji", + + "toast.session.listFailed.title": "Nie udało się załadować sesji dla {{project}}", + + "toast.update.title": "Dostępna aktualizacja", + "toast.update.description": "Nowa wersja OpenCode ({{version}}) jest teraz dostępna do instalacji.", + "toast.update.action.installRestart": "Zainstaluj i zrestartuj", + "toast.update.action.notYet": "Jeszcze nie", + + "error.page.title": "Coś poszło nie tak", + "error.page.description": "Wystąpił błąd podczas ładowania aplikacji.", + "error.page.details.label": "Szczegóły błędu", + "error.page.action.restart": "Restartuj", + "error.page.action.checking": "Sprawdzanie...", + "error.page.action.checkUpdates": "Sprawdź aktualizacje", + "error.page.action.updateTo": "Zaktualizuj do {{version}}", + "error.page.report.prefix": "Proszę zgłosić ten błąd do zespołu OpenCode", + "error.page.report.discord": "na Discordzie", + "error.page.version": "Wersja: {{version}}", + + "error.dev.rootNotFound": + "Nie znaleziono elementu głównego. Czy zapomniałeś dodać go do swojego index.html? A może atrybut id został błędnie wpisany?", + + "error.globalSync.connectFailed": "Nie można połączyć się z serwerem. Czy serwer działa pod adresem `{{url}}`?", + + "error.chain.unknown": "Nieznany błąd", + "error.chain.causedBy": "Spowodowany przez:", + "error.chain.apiError": "Błąd API", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Można ponowić: {{retryable}}", + "error.chain.responseBody": "Treść odpowiedzi:\n{{body}}", + "error.chain.didYouMean": "Czy miałeś na myśli: {{suggestions}}", + "error.chain.modelNotFound": "Model nie znaleziony: {{provider}}/{{model}}", + "error.chain.checkConfig": "Sprawdź swoją konfigurację (opencode.json) nazwy dostawców/modeli", + "error.chain.mcpFailed": + 'Serwer MCP "{{name}}" nie powiódł się. Uwaga, OpenCode nie obsługuje jeszcze uwierzytelniania MCP.', + "error.chain.providerAuthFailed": "Uwierzytelnianie dostawcy nie powiodło się ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Nie udało się zainicjować dostawcy "{{provider}}". Sprawdź poświadczenia i konfigurację.', + "error.chain.configJsonInvalid": "Plik konfiguracyjny w {{path}} nie jest poprawnym JSON(C)", + "error.chain.configJsonInvalidWithMessage": "Plik konfiguracyjny w {{path}} nie jest poprawnym JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Katalog "{{dir}}" w {{path}} jest nieprawidłowy. Zmień nazwę katalogu na "{{suggestion}}" lub usuń go. To częsta literówka.', + "error.chain.configFrontmatterError": "Nie udało się przetworzyć frontmatter w {{path}}:\n{{message}}", + "error.chain.configInvalid": "Plik konfiguracyjny w {{path}} jest nieprawidłowy", + "error.chain.configInvalidWithMessage": "Plik konfiguracyjny w {{path}} jest nieprawidłowy: {{message}}", + + "notification.permission.title": "Wymagane uprawnienie", + "notification.permission.description": "{{sessionTitle}} w {{projectName}} potrzebuje uprawnienia", + "notification.question.title": "Pytanie", + "notification.question.description": "{{sessionTitle}} w {{projectName}} ma pytanie", + "notification.action.goToSession": "Przejdź do sesji", + + "notification.session.responseReady.title": "Odpowiedź gotowa", + "notification.session.error.title": "Błąd sesji", + "notification.session.error.fallbackDescription": "Wystąpił błąd", + + "home.recentProjects": "Ostatnie projekty", + "home.empty.title": "Brak ostatnich projektów", + "home.empty.description": "Zacznij od otwarcia lokalnego projektu", + + "session.tab.session": "Sesja", + "session.tab.review": "Przegląd", + "session.tab.context": "Kontekst", + "session.panel.reviewAndFiles": "Przegląd i pliki", + "session.review.filesChanged": "Zmieniono {{count}} plików", + "session.review.loadingChanges": "Ładowanie zmian...", + "session.review.empty": "Brak zmian w tej sesji", + "session.messages.renderEarlier": "Renderuj wcześniejsze wiadomości", + "session.messages.loadingEarlier": "Ładowanie wcześniejszych wiadomości...", + "session.messages.loadEarlier": "Załaduj wcześniejsze wiadomości", + "session.messages.loading": "Ładowanie wiadomości...", + "session.messages.jumpToLatest": "Przejdź do najnowszych", + + "session.context.addToContext": "Dodaj {{selection}} do kontekstu", + + "session.new.worktree.main": "Główna gałąź", + "session.new.worktree.mainWithBranch": "Główna gałąź ({{branch}})", + "session.new.worktree.create": "Utwórz nowe drzewo robocze", + "session.new.lastModified": "Ostatnio zmodyfikowano", + + "session.header.search.placeholder": "Szukaj {{project}}", + "session.header.searchFiles": "Szukaj plików", + + "session.share.popover.title": "Opublikuj w sieci", + "session.share.popover.description.shared": + "Ta sesja jest publiczna w sieci. Jest dostępna dla każdego, kto posiada link.", + "session.share.popover.description.unshared": + "Udostępnij sesję publicznie w sieci. Będzie dostępna dla każdego, kto posiada link.", + "session.share.action.share": "Udostępnij", + "session.share.action.publish": "Opublikuj", + "session.share.action.publishing": "Publikowanie...", + "session.share.action.unpublish": "Cofnij publikację", + "session.share.action.unpublishing": "Cofanie publikacji...", + "session.share.action.view": "Widok", + "session.share.copy.copied": "Skopiowano", + "session.share.copy.copyLink": "Kopiuj link", + + "lsp.tooltip.none": "Brak serwerów LSP", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Ładowanie promptu...", + "terminal.loading": "Ładowanie terminala...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Zamknij terminal", + "terminal.connectionLost.title": "Utracono połączenie", + "terminal.connectionLost.description": + "Połączenie z terminalem zostało przerwane. Może się to zdarzyć przy restarcie serwera.", + + "common.closeTab": "Zamknij kartę", + "common.dismiss": "Odrzuć", + "common.requestFailed": "Żądanie nie powiodło się", + "common.moreOptions": "Więcej opcji", + "common.learnMore": "Dowiedz się więcej", + "common.rename": "Zmień nazwę", + "common.reset": "Resetuj", + "common.archive": "Archiwizuj", + "common.delete": "Usuń", + "common.close": "Zamknij", + "common.edit": "Edytuj", + "common.loadMore": "Załaduj więcej", + "common.key.esc": "ESC", + + "sidebar.menu.toggle": "Przełącz menu", + "sidebar.nav.projectsAndSessions": "Projekty i sesje", + "sidebar.settings": "Ustawienia", + "sidebar.help": "Pomoc", + "sidebar.workspaces.enable": "Włącz przestrzenie robocze", + "sidebar.workspaces.disable": "Wyłącz przestrzenie robocze", + "sidebar.gettingStarted.title": "Pierwsze kroki", + "sidebar.gettingStarted.line1": "OpenCode zawiera darmowe modele, więc możesz zacząć od razu.", + "sidebar.gettingStarted.line2": "Połącz dowolnego dostawcę, aby używać modeli, w tym Claude, GPT, Gemini itp.", + "sidebar.project.recentSessions": "Ostatnie sesje", + "sidebar.project.viewAllSessions": "Zobacz wszystkie sesje", + + "settings.section.desktop": "Pulpit", + "settings.tab.general": "Ogólne", + "settings.tab.shortcuts": "Skróty", + + "settings.general.section.appearance": "Wygląd", + "settings.general.section.notifications": "Powiadomienia systemowe", + "settings.general.section.sounds": "Efekty dźwiękowe", + + "settings.general.row.language.title": "Język", + "settings.general.row.language.description": "Zmień język wyświetlania dla OpenCode", + "settings.general.row.appearance.title": "Wygląd", + "settings.general.row.appearance.description": "Dostosuj wygląd OpenCode na swoim urządzeniu", + "settings.general.row.theme.title": "Motyw", + "settings.general.row.theme.description": "Dostosuj motyw OpenCode.", + "settings.general.row.font.title": "Czcionka", + "settings.general.row.font.description": "Dostosuj czcionkę mono używaną w blokach kodu", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "sound.option.alert01": "Alert 01", + "sound.option.alert02": "Alert 02", + "sound.option.alert03": "Alert 03", + "sound.option.alert04": "Alert 04", + "sound.option.alert05": "Alert 05", + "sound.option.alert06": "Alert 06", + "sound.option.alert07": "Alert 07", + "sound.option.alert08": "Alert 08", + "sound.option.alert09": "Alert 09", + "sound.option.alert10": "Alert 10", + "sound.option.bipbop01": "Bip-bop 01", + "sound.option.bipbop02": "Bip-bop 02", + "sound.option.bipbop03": "Bip-bop 03", + "sound.option.bipbop04": "Bip-bop 04", + "sound.option.bipbop05": "Bip-bop 05", + "sound.option.bipbop06": "Bip-bop 06", + "sound.option.bipbop07": "Bip-bop 07", + "sound.option.bipbop08": "Bip-bop 08", + "sound.option.bipbop09": "Bip-bop 09", + "sound.option.bipbop10": "Bip-bop 10", + "sound.option.staplebops01": "Staplebops 01", + "sound.option.staplebops02": "Staplebops 02", + "sound.option.staplebops03": "Staplebops 03", + "sound.option.staplebops04": "Staplebops 04", + "sound.option.staplebops05": "Staplebops 05", + "sound.option.staplebops06": "Staplebops 06", + "sound.option.staplebops07": "Staplebops 07", + "sound.option.nope01": "Nope 01", + "sound.option.nope02": "Nope 02", + "sound.option.nope03": "Nope 03", + "sound.option.nope04": "Nope 04", + "sound.option.nope05": "Nope 05", + "sound.option.nope06": "Nope 06", + "sound.option.nope07": "Nope 07", + "sound.option.nope08": "Nope 08", + "sound.option.nope09": "Nope 09", + "sound.option.nope10": "Nope 10", + "sound.option.nope11": "Nope 11", + "sound.option.nope12": "Nope 12", + "sound.option.yup01": "Yup 01", + "sound.option.yup02": "Yup 02", + "sound.option.yup03": "Yup 03", + "sound.option.yup04": "Yup 04", + "sound.option.yup05": "Yup 05", + "sound.option.yup06": "Yup 06", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Pokaż powiadomienie systemowe, gdy agent zakończy pracę lub wymaga uwagi", + "settings.general.notifications.permissions.title": "Uprawnienia", + "settings.general.notifications.permissions.description": + "Pokaż powiadomienie systemowe, gdy wymagane jest uprawnienie", + "settings.general.notifications.errors.title": "Błędy", + "settings.general.notifications.errors.description": "Pokaż powiadomienie systemowe, gdy wystąpi błąd", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Odtwórz dźwięk, gdy agent zakończy pracę lub wymaga uwagi", + "settings.general.sounds.permissions.title": "Uprawnienia", + "settings.general.sounds.permissions.description": "Odtwórz dźwięk, gdy wymagane jest uprawnienie", + "settings.general.sounds.errors.title": "Błędy", + "settings.general.sounds.errors.description": "Odtwórz dźwięk, gdy wystąpi błąd", + + "settings.shortcuts.title": "Skróty klawiszowe", + "settings.shortcuts.reset.button": "Przywróć domyślne", + "settings.shortcuts.reset.toast.title": "Zresetowano skróty", + "settings.shortcuts.reset.toast.description": "Skróty klawiszowe zostały przywrócone do ustawień domyślnych.", + "settings.shortcuts.conflict.title": "Skrót już w użyciu", + "settings.shortcuts.conflict.description": "{{keybind}} jest już przypisany do {{titles}}.", + "settings.shortcuts.unassigned": "Nieprzypisany", + "settings.shortcuts.pressKeys": "Naciśnij klawisze", + "settings.shortcuts.search.placeholder": "Szukaj skrótów", + "settings.shortcuts.search.empty": "Nie znaleziono skrótów", + + "settings.shortcuts.group.general": "Ogólne", + "settings.shortcuts.group.session": "Sesja", + "settings.shortcuts.group.navigation": "Nawigacja", + "settings.shortcuts.group.modelAndAgent": "Model i agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Dostawcy", + "settings.providers.description": "Ustawienia dostawców będą tutaj konfigurowalne.", + "settings.models.title": "Modele", + "settings.models.description": "Ustawienia modeli będą tutaj konfigurowalne.", + "settings.agents.title": "Agenci", + "settings.agents.description": "Ustawienia agentów będą tutaj konfigurowalne.", + "settings.commands.title": "Polecenia", + "settings.commands.description": "Ustawienia poleceń będą tutaj konfigurowalne.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "Ustawienia MCP będą tutaj konfigurowalne.", + + "settings.permissions.title": "Uprawnienia", + "settings.permissions.description": "Kontroluj, jakich narzędzi serwer może używać domyślnie.", + "settings.permissions.section.tools": "Narzędzia", + "settings.permissions.toast.updateFailed.title": "Nie udało się zaktualizować uprawnień", + + "settings.permissions.action.allow": "Zezwól", + "settings.permissions.action.ask": "Pytaj", + "settings.permissions.action.deny": "Odmów", + + "settings.permissions.tool.read.title": "Odczyt", + "settings.permissions.tool.read.description": "Odczyt pliku (pasuje do ścieżki pliku)", + "settings.permissions.tool.edit.title": "Edycja", + "settings.permissions.tool.edit.description": "Modyfikacja plików, w tym edycje, zapisy, łatki i multi-edycje", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Dopasowywanie plików za pomocą wzorców glob", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Przeszukiwanie zawartości plików za pomocą wyrażeń regularnych", + "settings.permissions.tool.list.title": "Lista", + "settings.permissions.tool.list.description": "Wyświetlanie listy plików w katalogu", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Uruchamianie poleceń powłoki", + "settings.permissions.tool.task.title": "Zadanie", + "settings.permissions.tool.task.description": "Uruchamianie pod-agentów", + "settings.permissions.tool.skill.title": "Umiejętność", + "settings.permissions.tool.skill.description": "Ładowanie umiejętności według nazwy", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Uruchamianie zapytań serwera językowego", + "settings.permissions.tool.todoread.title": "Odczyt Todo", + "settings.permissions.tool.todoread.description": "Odczyt listy zadań", + "settings.permissions.tool.todowrite.title": "Zapis Todo", + "settings.permissions.tool.todowrite.description": "Aktualizacja listy zadań", + "settings.permissions.tool.webfetch.title": "Pobieranie z sieci", + "settings.permissions.tool.webfetch.description": "Pobieranie zawartości z adresu URL", + "settings.permissions.tool.websearch.title": "Wyszukiwanie w sieci", + "settings.permissions.tool.websearch.description": "Przeszukiwanie sieci", + "settings.permissions.tool.codesearch.title": "Wyszukiwanie kodu", + "settings.permissions.tool.codesearch.description": "Przeszukiwanie kodu w sieci", + "settings.permissions.tool.external_directory.title": "Katalog zewnętrzny", + "settings.permissions.tool.external_directory.description": "Dostęp do plików poza katalogiem projektu", + "settings.permissions.tool.doom_loop.title": "Zapętlenie", + "settings.permissions.tool.doom_loop.description": "Wykrywanie powtarzających się wywołań narzędzi (doom loop)", + + "session.delete.failed.title": "Nie udało się usunąć sesji", + "session.delete.title": "Usuń sesję", + "session.delete.confirm": 'Usunąć sesję "{{name}}"?', + "session.delete.button": "Usuń sesję", + + "workspace.new": "Nowa przestrzeń robocza", + "workspace.type.local": "lokalna", + "workspace.type.sandbox": "piaskownica", + "workspace.create.failed.title": "Nie udało się utworzyć przestrzeni roboczej", + "workspace.delete.failed.title": "Nie udało się usunąć przestrzeni roboczej", + "workspace.resetting.title": "Resetowanie przestrzeni roboczej", + "workspace.resetting.description": "To może potrwać minutę.", + "workspace.reset.failed.title": "Nie udało się zresetować przestrzeni roboczej", + "workspace.reset.success.title": "Przestrzeń robocza zresetowana", + "workspace.reset.success.description": "Przestrzeń robocza odpowiada teraz domyślnej gałęzi.", + "workspace.status.checking": "Sprawdzanie niezscalonych zmian...", + "workspace.status.error": "Nie można zweryfikować statusu git.", + "workspace.status.clean": "Nie wykryto niezscalonych zmian.", + "workspace.status.dirty": "Wykryto niezscalone zmiany w tej przestrzeni roboczej.", + "workspace.delete.title": "Usuń przestrzeń roboczą", + "workspace.delete.confirm": 'Usunąć przestrzeń roboczą "{{name}}"?', + "workspace.delete.button": "Usuń przestrzeń roboczą", + "workspace.reset.title": "Resetuj przestrzeń roboczą", + "workspace.reset.confirm": 'Zresetować przestrzeń roboczą "{{name}}"?', + "workspace.reset.button": "Resetuj przestrzeń roboczą", + "workspace.reset.archived.none": "Żadne aktywne sesje nie zostaną zarchiwizowane.", + "workspace.reset.archived.one": "1 sesja zostanie zarchiwizowana.", + "workspace.reset.archived.many": "{{count}} sesji zostanie zarchiwizowanych.", + "workspace.reset.note": "To zresetuje przestrzeń roboczą, aby odpowiadała domyślnej gałęzi.", +} diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts new file mode 100644 index 00000000000..dd399e27cf4 --- /dev/null +++ b/packages/app/src/i18n/ru.ts @@ -0,0 +1,662 @@ +export const dict = { + "command.category.suggested": "Предложено", + "command.category.view": "Просмотр", + "command.category.project": "Проект", + "command.category.provider": "Провайдер", + "command.category.server": "Сервер", + "command.category.session": "Сессия", + "command.category.theme": "Тема", + "command.category.language": "Язык", + "command.category.file": "Файл", + "command.category.terminal": "Терминал", + "command.category.model": "Модель", + "command.category.mcp": "MCP", + "command.category.agent": "Агент", + "command.category.permissions": "Разрешения", + "command.category.workspace": "Рабочее пространство", + "command.category.settings": "Настройки", + + "theme.scheme.system": "Системная", + "theme.scheme.light": "Светлая", + "theme.scheme.dark": "Тёмная", + + "command.sidebar.toggle": "Переключить боковую панель", + "command.project.open": "Открыть проект", + "command.provider.connect": "Подключить провайдера", + "command.server.switch": "Переключить сервер", + "command.settings.open": "Открыть настройки", + "command.session.previous": "Предыдущая сессия", + "command.session.next": "Следующая сессия", + "command.session.archive": "Архивировать сессию", + + "command.palette": "Палитра команд", + + "command.theme.cycle": "Цикл тем", + "command.theme.set": "Использовать тему: {{theme}}", + "command.theme.scheme.cycle": "Цикл цветовой схемы", + "command.theme.scheme.set": "Использовать цветовую схему: {{scheme}}", + + "command.language.cycle": "Цикл языков", + "command.language.set": "Использовать язык: {{language}}", + + "command.session.new": "Новая сессия", + "command.file.open": "Открыть файл", + "command.file.open.description": "Поиск файлов и команд", + "command.terminal.toggle": "Переключить терминал", + "command.review.toggle": "Переключить обзор", + "command.terminal.new": "Новый терминал", + "command.terminal.new.description": "Создать новую вкладку терминала", + "command.steps.toggle": "Переключить шаги", + "command.steps.toggle.description": "Показать или скрыть шаги для текущего сообщения", + "command.message.previous": "Предыдущее сообщение", + "command.message.previous.description": "Перейти к предыдущему сообщению пользователя", + "command.message.next": "Следующее сообщение", + "command.message.next.description": "Перейти к следующему сообщению пользователя", + "command.model.choose": "Выбрать модель", + "command.model.choose.description": "Выбрать другую модель", + "command.mcp.toggle": "Переключить MCP", + "command.mcp.toggle.description": "Переключить MCP", + "command.agent.cycle": "Цикл агентов", + "command.agent.cycle.description": "Переключиться к следующему агенту", + "command.agent.cycle.reverse": "Цикл агентов назад", + "command.agent.cycle.reverse.description": "Переключиться к предыдущему агенту", + "command.model.variant.cycle": "Цикл режимов мышления", + "command.model.variant.cycle.description": "Переключиться к следующему уровню усилий", + "command.permissions.autoaccept.enable": "Авто-принятие изменений", + "command.permissions.autoaccept.disable": "Прекратить авто-принятие изменений", + "command.session.undo": "Отменить", + "command.session.undo.description": "Отменить последнее сообщение", + "command.session.redo": "Повторить", + "command.session.redo.description": "Повторить отменённое сообщение", + "command.session.compact": "Сжать сессию", + "command.session.compact.description": "Сократить сессию для уменьшения размера контекста", + "command.session.fork": "Создать ответвление", + "command.session.fork.description": "Создать новую сессию из сообщения", + "command.session.share": "Поделиться сессией", + "command.session.share.description": "Поделиться сессией и скопировать URL в буфер обмена", + "command.session.unshare": "Отменить публикацию", + "command.session.unshare.description": "Прекратить публикацию сессии", + + "palette.search.placeholder": "Поиск файлов и команд", + "palette.empty": "Ничего не найдено", + "palette.group.commands": "Команды", + "palette.group.files": "Файлы", + + "dialog.provider.search.placeholder": "Поиск провайдеров", + "dialog.provider.empty": "Провайдеры не найдены", + "dialog.provider.group.popular": "Популярные", + "dialog.provider.group.other": "Другие", + "dialog.provider.tag.recommended": "Рекомендуемые", + "dialog.provider.anthropic.note": "Подключитесь с помощью Claude Pro/Max или API ключа", + + "dialog.model.select.title": "Выбрать модель", + "dialog.model.search.placeholder": "Поиск моделей", + "dialog.model.empty": "Модели не найдены", + "dialog.model.manage": "Управление моделями", + "dialog.model.manage.description": "Настройте какие модели появляются в выборе модели", + + "dialog.model.unpaid.freeModels.title": "Бесплатные модели от OpenCode", + "dialog.model.unpaid.addMore.title": "Добавьте больше моделей от популярных провайдеров", + + "dialog.provider.viewAll": "Посмотреть всех провайдеров", + + "provider.connect.title": "Подключить {{provider}}", + "provider.connect.title.anthropicProMax": "Войти с помощью Claude Pro/Max", + "provider.connect.selectMethod": "Выберите способ входа для {{provider}}.", + "provider.connect.method.apiKey": "API ключ", + "provider.connect.status.inProgress": "Авторизация...", + "provider.connect.status.waiting": "Ожидание авторизации...", + "provider.connect.status.failed": "Ошибка авторизации: {{error}}", + "provider.connect.apiKey.description": + "Введите ваш API ключ {{provider}} для подключения аккаунта и использования моделей {{provider}} в OpenCode.", + "provider.connect.apiKey.label": "{{provider}} API ключ", + "provider.connect.apiKey.placeholder": "API ключ", + "provider.connect.apiKey.required": "API ключ обязателен", + "provider.connect.opencodeZen.line1": + "OpenCode Zen даёт вам доступ к отобранным надёжным оптимизированным моделям для агентов программирования.", + "provider.connect.opencodeZen.line2": + "С одним API ключом вы получите доступ к таким моделям как Claude, GPT, Gemini, GLM и другим.", + "provider.connect.opencodeZen.visit.prefix": "Посетите ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " чтобы получить ваш API ключ.", + "provider.connect.oauth.code.visit.prefix": "Посетите ", + "provider.connect.oauth.code.visit.link": "эту ссылку", + "provider.connect.oauth.code.visit.suffix": + " чтобы получить код авторизации для подключения аккаунта и использования моделей {{provider}} в OpenCode.", + "provider.connect.oauth.code.label": "{{method}} код авторизации", + "provider.connect.oauth.code.placeholder": "Код авторизации", + "provider.connect.oauth.code.required": "Код авторизации обязателен", + "provider.connect.oauth.code.invalid": "Неверный код авторизации", + "provider.connect.oauth.auto.visit.prefix": "Посетите ", + "provider.connect.oauth.auto.visit.link": "эту ссылку", + "provider.connect.oauth.auto.visit.suffix": + " и введите код ниже для подключения аккаунта и использования моделей {{provider}} в OpenCode.", + "provider.connect.oauth.auto.confirmationCode": "Код подтверждения", + "provider.connect.toast.connected.title": "{{provider}} подключён", + "provider.connect.toast.connected.description": "Модели {{provider}} теперь доступны.", + + "model.tag.free": "Бесплатно", + "model.tag.latest": "Последняя", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "текст", + "model.input.image": "изображение", + "model.input.audio": "аудио", + "model.input.video": "видео", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Разрешено: {{inputs}}", + "model.tooltip.reasoning.allowed": "Разрешает рассуждение", + "model.tooltip.reasoning.none": "Без рассуждения", + "model.tooltip.context": "Лимит контекста {{limit}}", + + "common.search.placeholder": "Поиск", + "common.goBack": "Назад", + "common.loading": "Загрузка", + "common.loading.ellipsis": "...", + "common.cancel": "Отмена", + "common.submit": "Отправить", + "common.save": "Сохранить", + "common.saving": "Сохранение...", + "common.default": "По умолчанию", + "common.attachment": "вложение", + + "prompt.placeholder.shell": "Введите команду оболочки...", + "prompt.placeholder.normal": 'Спросите что угодно... "{{example}}"', + "prompt.mode.shell": "Оболочка", + "prompt.mode.shell.exit": "esc для выхода", + + "prompt.example.1": "Исправить TODO в коде", + "prompt.example.2": "Какой технологический стек этого проекта?", + "prompt.example.3": "Исправить сломанные тесты", + "prompt.example.4": "Объясни как работает аутентификация", + "prompt.example.5": "Найти и исправить уязвимости безопасности", + "prompt.example.6": "Добавить юнит-тесты для сервиса пользователя", + "prompt.example.7": "Рефакторить эту функцию для лучшей читаемости", + "prompt.example.8": "Что означает эта ошибка?", + "prompt.example.9": "Помоги мне отладить эту проблему", + "prompt.example.10": "Сгенерировать документацию API", + "prompt.example.11": "Оптимизировать запросы к базе данных", + "prompt.example.12": "Добавить валидацию ввода", + "prompt.example.13": "Создать новый компонент для...", + "prompt.example.14": "Как развернуть этот проект?", + "prompt.example.15": "Проверь мой код на лучшие практики", + "prompt.example.16": "Добавить обработку ошибок в эту функцию", + "prompt.example.17": "Объясни этот паттерн regex", + "prompt.example.18": "Конвертировать это в TypeScript", + "prompt.example.19": "Добавить логирование по всему проекту", + "prompt.example.20": "Какие зависимости устарели?", + "prompt.example.21": "Помоги написать скрипт миграции", + "prompt.example.22": "Реализовать кэширование для этой конечной точки", + "prompt.example.23": "Добавить пагинацию в этот список", + "prompt.example.24": "Создать CLI команду для...", + "prompt.example.25": "Как работают переменные окружения здесь?", + + "prompt.popover.emptyResults": "Нет совпадений", + "prompt.popover.emptyCommands": "Нет совпадающих команд", + "prompt.dropzone.label": "Перетащите изображения или PDF сюда", + "prompt.slash.badge.custom": "своё", + "prompt.context.active": "активно", + "prompt.context.includeActiveFile": "Включить активный файл", + "prompt.context.removeActiveFile": "Удалить активный файл из контекста", + "prompt.context.removeFile": "Удалить файл из контекста", + "prompt.action.attachFile": "Прикрепить файл", + "prompt.attachment.remove": "Удалить вложение", + "prompt.action.send": "Отправить", + "prompt.action.stop": "Остановить", + + "prompt.toast.pasteUnsupported.title": "Неподдерживаемая вставка", + "prompt.toast.pasteUnsupported.description": "Сюда можно вставлять только изображения или PDF.", + "prompt.toast.modelAgentRequired.title": "Выберите агента и модель", + "prompt.toast.modelAgentRequired.description": "Выберите агента и модель перед отправкой запроса.", + "prompt.toast.worktreeCreateFailed.title": "Не удалось создать worktree", + "prompt.toast.sessionCreateFailed.title": "Не удалось создать сессию", + "prompt.toast.shellSendFailed.title": "Не удалось отправить команду оболочки", + "prompt.toast.commandSendFailed.title": "Не удалось отправить команду", + "prompt.toast.promptSendFailed.title": "Не удалось отправить запрос", + + "dialog.mcp.title": "MCP", + "dialog.mcp.description": "{{enabled}} из {{total}} включено", + "dialog.mcp.empty": "MCP не настроены", + + "mcp.status.connected": "подключено", + "mcp.status.failed": "ошибка", + "mcp.status.needs_auth": "требуется авторизация", + "mcp.status.disabled": "отключено", + + "dialog.fork.empty": "Нет сообщений для ответвления", + + "dialog.directory.search.placeholder": "Поиск папок", + "dialog.directory.empty": "Папки не найдены", + + "dialog.server.title": "Серверы", + "dialog.server.description": "Переключите сервер OpenCode к которому подключается приложение.", + "dialog.server.search.placeholder": "Поиск серверов", + "dialog.server.empty": "Серверов пока нет", + "dialog.server.add.title": "Добавить сервер", + "dialog.server.add.url": "URL сервера", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Не удалось подключиться к серверу", + "dialog.server.add.checking": "Проверка...", + "dialog.server.add.button": "Добавить", + "dialog.server.default.title": "Сервер по умолчанию", + "dialog.server.default.description": + "Подключаться к этому серверу при запуске приложения вместо запуска локального сервера. Требуется перезапуск.", + "dialog.server.default.none": "Сервер не выбран", + "dialog.server.default.set": "Установить текущий сервер по умолчанию", + "dialog.server.default.clear": "Очистить", + "dialog.server.action.remove": "Удалить сервер", + + "dialog.project.edit.title": "Редактировать проект", + "dialog.project.edit.name": "Название", + "dialog.project.edit.icon": "Иконка", + "dialog.project.edit.icon.alt": "Иконка проекта", + "dialog.project.edit.icon.hint": "Нажмите или перетащите изображение", + "dialog.project.edit.icon.recommended": "Рекомендуется: 128x128px", + "dialog.project.edit.color": "Цвет", + "dialog.project.edit.color.select": "Выбрать цвет {{color}}", + + "context.breakdown.title": "Разбивка контекста", + "context.breakdown.note": + 'Приблизительная разбивка входных токенов. "Другое" включает определения инструментов и накладные расходы.', + "context.breakdown.system": "Система", + "context.breakdown.user": "Пользователь", + "context.breakdown.assistant": "Ассистент", + "context.breakdown.tool": "Вызовы инструментов", + "context.breakdown.other": "Другое", + + "context.systemPrompt.title": "Системный промпт", + "context.rawMessages.title": "Исходные сообщения", + + "context.stats.session": "Сессия", + "context.stats.messages": "Сообщения", + "context.stats.provider": "Провайдер", + "context.stats.model": "Модель", + "context.stats.limit": "Лимит контекста", + "context.stats.totalTokens": "Всего токенов", + "context.stats.usage": "Использование", + "context.stats.inputTokens": "Входные токены", + "context.stats.outputTokens": "Выходные токены", + "context.stats.reasoningTokens": "Токены рассуждения", + "context.stats.cacheTokens": "Токены кэша (чтение/запись)", + "context.stats.userMessages": "Сообщения пользователя", + "context.stats.assistantMessages": "Сообщения ассистента", + "context.stats.totalCost": "Общая стоимость", + "context.stats.sessionCreated": "Сессия создана", + "context.stats.lastActivity": "Последняя активность", + + "context.usage.tokens": "Токены", + "context.usage.usage": "Использование", + "context.usage.cost": "Стоимость", + "context.usage.clickToView": "Нажмите для просмотра контекста", + "context.usage.view": "Показать использование контекста", + + "language.en": "Английский", + "language.zh": "Китайский", + "language.ko": "Корейский", + "language.de": "Немецкий", + "language.es": "Испанский", + "language.fr": "Французский", + "language.ja": "Японский", + "language.da": "Датский", + "language.ru": "Русский", + "language.ar": "Арабский", + "language.no": "Норвежский", + "language.br": "Португальский (Бразилия)", + + "toast.language.title": "Язык", + "toast.language.description": "Переключено на {{language}}", + + "toast.theme.title": "Тема переключена", + "toast.scheme.title": "Цветовая схема", + + "toast.permissions.autoaccept.on.title": "Авто-принятие изменений", + "toast.permissions.autoaccept.on.description": "Разрешения на редактирование и запись будут автоматически одобрены", + "toast.permissions.autoaccept.off.title": "Авто-принятие остановлено", + "toast.permissions.autoaccept.off.description": "Редактирование и запись потребуют подтверждения", + + "toast.model.none.title": "Модель не выбрана", + "toast.model.none.description": "Подключите провайдера для суммаризации сессии", + + "toast.file.loadFailed.title": "Не удалось загрузить файл", + + "toast.session.share.copyFailed.title": "Не удалось скопировать URL в буфер обмена", + "toast.session.share.success.title": "Сессия опубликована", + "toast.session.share.success.description": "URL скопирован в буфер обмена!", + "toast.session.share.failed.title": "Не удалось опубликовать сессию", + "toast.session.share.failed.description": "Произошла ошибка при публикации сессии", + + "toast.session.unshare.success.title": "Публикация отменена", + "toast.session.unshare.success.description": "Публикация успешно отменена!", + "toast.session.unshare.failed.title": "Не удалось отменить публикацию", + "toast.session.unshare.failed.description": "Произошла ошибка при отмене публикации", + + "toast.session.listFailed.title": "Не удалось загрузить сессии для {{project}}", + + "toast.update.title": "Доступно обновление", + "toast.update.description": "Новая версия OpenCode ({{version}}) доступна для установки.", + "toast.update.action.installRestart": "Установить и перезапустить", + "toast.update.action.notYet": "Пока нет", + + "error.page.title": "Что-то пошло не так", + "error.page.description": "Произошла ошибка при загрузке приложения.", + "error.page.details.label": "Детали ошибки", + "error.page.action.restart": "Перезапустить", + "error.page.action.checking": "Проверка...", + "error.page.action.checkUpdates": "Проверить обновления", + "error.page.action.updateTo": "Обновить до {{version}}", + "error.page.report.prefix": "Пожалуйста, сообщите об этой ошибке команде OpenCode", + "error.page.report.discord": "в Discord", + "error.page.version": "Версия: {{version}}", + + "error.dev.rootNotFound": + "Корневой элемент не найден. Вы забыли добавить его в index.html? Или, может быть, атрибут id был написан неправильно?", + + "error.globalSync.connectFailed": "Не удалось подключиться к серверу. Запущен ли сервер по адресу `{{url}}`?", + + "error.chain.unknown": "Неизвестная ошибка", + "error.chain.causedBy": "Причина:", + "error.chain.apiError": "Ошибка API", + "error.chain.status": "Статус: {{status}}", + "error.chain.retryable": "Повторная попытка: {{retryable}}", + "error.chain.responseBody": "Тело ответа:\n{{body}}", + "error.chain.didYouMean": "Возможно, вы имели в виду: {{suggestions}}", + "error.chain.modelNotFound": "Модель не найдена: {{provider}}/{{model}}", + "error.chain.checkConfig": "Проверьте названия провайдера/модели в конфиге (opencode.json)", + "error.chain.mcpFailed": + 'MCP сервер "{{name}}" завершился с ошибкой. Обратите внимание, что OpenCode пока не поддерживает MCP авторизацию.', + "error.chain.providerAuthFailed": "Ошибка аутентификации провайдера ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Не удалось инициализировать провайдера "{{provider}}". Проверьте учётные данные и конфигурацию.', + "error.chain.configJsonInvalid": "Конфигурационный файл по адресу {{path}} не является валидным JSON(C)", + "error.chain.configJsonInvalidWithMessage": + "Конфигурационный файл по адресу {{path}} не является валидным JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Папка "{{dir}}" в {{path}} невалидна. Переименуйте папку в "{{suggestion}}" или удалите её. Это распространённая опечатка.', + "error.chain.configFrontmatterError": "Не удалось разобрать frontmatter в {{path}}:\n{{message}}", + "error.chain.configInvalid": "Конфигурационный файл по адресу {{path}} невалиден", + "error.chain.configInvalidWithMessage": "Конфигурационный файл по адресу {{path}} невалиден: {{message}}", + + "notification.permission.title": "Требуется разрешение", + "notification.permission.description": "{{sessionTitle}} в {{projectName}} требуется разрешение", + "notification.question.title": "Вопрос", + "notification.question.description": "У {{sessionTitle}} в {{projectName}} есть вопрос", + "notification.action.goToSession": "Перейти к сессии", + + "notification.session.responseReady.title": "Ответ готов", + "notification.session.error.title": "Ошибка сессии", + "notification.session.error.fallbackDescription": "Произошла ошибка", + + "home.recentProjects": "Недавние проекты", + "home.empty.title": "Нет недавних проектов", + "home.empty.description": "Начните с открытия локального проекта", + + "session.tab.session": "Сессия", + "session.tab.review": "Обзор", + "session.tab.context": "Контекст", + "session.panel.reviewAndFiles": "Обзор и файлы", + "session.review.filesChanged": "{{count}} файлов изменено", + "session.review.loadingChanges": "Загрузка изменений...", + "session.review.empty": "Изменений в этой сессии пока нет", + "session.messages.renderEarlier": "Показать предыдущие сообщения", + "session.messages.loadingEarlier": "Загрузка предыдущих сообщений...", + "session.messages.loadEarlier": "Загрузить предыдущие сообщения", + "session.messages.loading": "Загрузка сообщений...", + "session.messages.jumpToLatest": "Перейти к последнему", + + "session.context.addToContext": "Добавить {{selection}} в контекст", + + "session.new.worktree.main": "Основная ветка", + "session.new.worktree.mainWithBranch": "Основная ветка ({{branch}})", + "session.new.worktree.create": "Создать новый worktree", + "session.new.lastModified": "Последнее изменение", + + "session.header.search.placeholder": "Поиск {{project}}", + "session.header.searchFiles": "Поиск файлов", + + "session.share.popover.title": "Опубликовать в интернете", + "session.share.popover.description.shared": + "Эта сессия общедоступна. Доступ к ней может получить любой, у кого есть ссылка.", + "session.share.popover.description.unshared": + "Опубликуйте сессию в интернете. Доступ к ней сможет получить любой, у кого есть ссылка.", + "session.share.action.share": "Поделиться", + "session.share.action.publish": "Опубликовать", + "session.share.action.publishing": "Публикация...", + "session.share.action.unpublish": "Отменить публикацию", + "session.share.action.unpublishing": "Отмена публикации...", + "session.share.action.view": "Посмотреть", + "session.share.copy.copied": "Скопировано", + "session.share.copy.copyLink": "Копировать ссылку", + + "lsp.tooltip.none": "Нет LSP серверов", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Загрузка запроса...", + "terminal.loading": "Загрузка терминала...", + "terminal.title": "Терминал", + "terminal.title.numbered": "Терминал {{number}}", + "terminal.close": "Закрыть терминал", + "terminal.connectionLost.title": "Соединение потеряно", + "terminal.connectionLost.description": + "Соединение с терминалом прервано. Это может произойти при перезапуске сервера.", + + "common.closeTab": "Закрыть вкладку", + "common.dismiss": "Закрыть", + "common.requestFailed": "Запрос не выполнен", + "common.moreOptions": "Дополнительные опции", + "common.learnMore": "Подробнее", + "common.rename": "Переименовать", + "common.reset": "Сбросить", + "common.archive": "Архивировать", + "common.delete": "Удалить", + "common.close": "Закрыть", + "common.edit": "Редактировать", + "common.loadMore": "Загрузить ещё", + "common.key.esc": "ESC", + + "sidebar.menu.toggle": "Переключить меню", + "sidebar.nav.projectsAndSessions": "Проекты и сессии", + "sidebar.settings": "Настройки", + "sidebar.help": "Помощь", + "sidebar.workspaces.enable": "Включить рабочие пространства", + "sidebar.workspaces.disable": "Отключить рабочие пространства", + "sidebar.gettingStarted.title": "Начало работы", + "sidebar.gettingStarted.line1": "OpenCode включает бесплатные модели, чтобы вы могли начать сразу.", + "sidebar.gettingStarted.line2": + "Подключите любого провайдера для использования моделей, включая Claude, GPT, Gemini и др.", + "sidebar.project.recentSessions": "Недавние сессии", + "sidebar.project.viewAllSessions": "Посмотреть все сессии", + + "settings.section.desktop": "Приложение", + "settings.tab.general": "Основные", + "settings.tab.shortcuts": "Горячие клавиши", + + "settings.general.section.appearance": "Внешний вид", + "settings.general.section.notifications": "Системные уведомления", + "settings.general.section.sounds": "Звуковые эффекты", + + "settings.general.row.language.title": "Язык", + "settings.general.row.language.description": "Изменить язык отображения OpenCode", + "settings.general.row.appearance.title": "Внешний вид", + "settings.general.row.appearance.description": "Настройте как OpenCode выглядит на вашем устройстве", + "settings.general.row.theme.title": "Тема", + "settings.general.row.theme.description": "Настройте оформление OpenCode.", + "settings.general.row.font.title": "Шрифт", + "settings.general.row.font.description": "Настройте моноширинный шрифт для блоков кода", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "sound.option.alert01": "Alert 01", + "sound.option.alert02": "Alert 02", + "sound.option.alert03": "Alert 03", + "sound.option.alert04": "Alert 04", + "sound.option.alert05": "Alert 05", + "sound.option.alert06": "Alert 06", + "sound.option.alert07": "Alert 07", + "sound.option.alert08": "Alert 08", + "sound.option.alert09": "Alert 09", + "sound.option.alert10": "Alert 10", + "sound.option.bipbop01": "Bip-bop 01", + "sound.option.bipbop02": "Bip-bop 02", + "sound.option.bipbop03": "Bip-bop 03", + "sound.option.bipbop04": "Bip-bop 04", + "sound.option.bipbop05": "Bip-bop 05", + "sound.option.bipbop06": "Bip-bop 06", + "sound.option.bipbop07": "Bip-bop 07", + "sound.option.bipbop08": "Bip-bop 08", + "sound.option.bipbop09": "Bip-bop 09", + "sound.option.bipbop10": "Bip-bop 10", + "sound.option.staplebops01": "Staplebops 01", + "sound.option.staplebops02": "Staplebops 02", + "sound.option.staplebops03": "Staplebops 03", + "sound.option.staplebops04": "Staplebops 04", + "sound.option.staplebops05": "Staplebops 05", + "sound.option.staplebops06": "Staplebops 06", + "sound.option.staplebops07": "Staplebops 07", + "sound.option.nope01": "Nope 01", + "sound.option.nope02": "Nope 02", + "sound.option.nope03": "Nope 03", + "sound.option.nope04": "Nope 04", + "sound.option.nope05": "Nope 05", + "sound.option.nope06": "Nope 06", + "sound.option.nope07": "Nope 07", + "sound.option.nope08": "Nope 08", + "sound.option.nope09": "Nope 09", + "sound.option.nope10": "Nope 10", + "sound.option.nope11": "Nope 11", + "sound.option.nope12": "Nope 12", + "sound.option.yup01": "Yup 01", + "sound.option.yup02": "Yup 02", + "sound.option.yup03": "Yup 03", + "sound.option.yup04": "Yup 04", + "sound.option.yup05": "Yup 05", + "sound.option.yup06": "Yup 06", + + "settings.general.notifications.agent.title": "Агент", + "settings.general.notifications.agent.description": + "Показывать системное уведомление когда агент завершён или требует внимания", + "settings.general.notifications.permissions.title": "Разрешения", + "settings.general.notifications.permissions.description": + "Показывать системное уведомление когда требуется разрешение", + "settings.general.notifications.errors.title": "Ошибки", + "settings.general.notifications.errors.description": "Показывать системное уведомление когда происходит ошибка", + + "settings.general.sounds.agent.title": "Агент", + "settings.general.sounds.agent.description": "Воспроизводить звук когда агент завершён или требует внимания", + "settings.general.sounds.permissions.title": "Разрешения", + "settings.general.sounds.permissions.description": "Воспроизводить звук когда требуется разрешение", + "settings.general.sounds.errors.title": "Ошибки", + "settings.general.sounds.errors.description": "Воспроизводить звук когда происходит ошибка", + + "settings.shortcuts.title": "Горячие клавиши", + "settings.shortcuts.reset.button": "Сбросить к умолчаниям", + "settings.shortcuts.reset.toast.title": "Горячие клавиши сброшены", + "settings.shortcuts.reset.toast.description": "Горячие клавиши были сброшены к значениям по умолчанию.", + "settings.shortcuts.conflict.title": "Сочетание уже используется", + "settings.shortcuts.conflict.description": "{{keybind}} уже назначено для {{titles}}.", + "settings.shortcuts.unassigned": "Не назначено", + "settings.shortcuts.pressKeys": "Нажмите клавиши", + "settings.shortcuts.search.placeholder": "Поиск горячих клавиш", + "settings.shortcuts.search.empty": "Горячие клавиши не найдены", + + "settings.shortcuts.group.general": "Основные", + "settings.shortcuts.group.session": "Сессия", + "settings.shortcuts.group.navigation": "Навигация", + "settings.shortcuts.group.modelAndAgent": "Модель и агент", + "settings.shortcuts.group.terminal": "Терминал", + "settings.shortcuts.group.prompt": "Запрос", + + "settings.providers.title": "Провайдеры", + "settings.providers.description": "Настройки провайдеров будут доступны здесь.", + "settings.models.title": "Модели", + "settings.models.description": "Настройки моделей будут доступны здесь.", + "settings.agents.title": "Агенты", + "settings.agents.description": "Настройки агентов будут доступны здесь.", + "settings.commands.title": "Команды", + "settings.commands.description": "Настройки команд будут доступны здесь.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "Настройки MCP будут доступны здесь.", + + "settings.permissions.title": "Разрешения", + "settings.permissions.description": "Контролируйте какие инструменты сервер может использовать по умолчанию.", + "settings.permissions.section.tools": "Инструменты", + "settings.permissions.toast.updateFailed.title": "Не удалось обновить разрешения", + + "settings.permissions.action.allow": "Разрешить", + "settings.permissions.action.ask": "Спрашивать", + "settings.permissions.action.deny": "Запретить", + + "settings.permissions.tool.read.title": "Чтение", + "settings.permissions.tool.read.description": "Чтение файла (по совпадению пути)", + "settings.permissions.tool.edit.title": "Редактирование", + "settings.permissions.tool.edit.description": + "Изменение файлов, включая редактирование, запись, патчи и мульти-редактирование", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Сопоставление файлов по паттернам glob", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Поиск по содержимому файлов с использованием регулярных выражений", + "settings.permissions.tool.list.title": "Список", + "settings.permissions.tool.list.description": "Список файлов в директории", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Выполнение команд оболочки", + "settings.permissions.tool.task.title": "Task", + "settings.permissions.tool.task.description": "Запуск под-агентов", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "Загрузить навык по имени", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Выполнение запросов к языковому серверу", + "settings.permissions.tool.todoread.title": "Чтение списка задач", + "settings.permissions.tool.todoread.description": "Чтение списка задач", + "settings.permissions.tool.todowrite.title": "Запись списка задач", + "settings.permissions.tool.todowrite.description": "Обновление списка задач", + "settings.permissions.tool.webfetch.title": "Web Fetch", + "settings.permissions.tool.webfetch.description": "Получить содержимое по URL", + "settings.permissions.tool.websearch.title": "Web Search", + "settings.permissions.tool.websearch.description": "Поиск в интернете", + "settings.permissions.tool.codesearch.title": "Поиск кода", + "settings.permissions.tool.codesearch.description": "Поиск кода в интернете", + "settings.permissions.tool.external_directory.title": "Внешняя директория", + "settings.permissions.tool.external_directory.description": "Доступ к файлам вне директории проекта", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "Обнаружение повторных вызовов инструментов с одинаковым вводом", + + "session.delete.failed.title": "Не удалось удалить сессию", + "session.delete.title": "Удалить сессию", + "session.delete.confirm": 'Удалить сессию "{{name}}"?', + "session.delete.button": "Удалить сессию", + + "workspace.new": "Новое рабочее пространство", + "workspace.type.local": "локальное", + "workspace.type.sandbox": "песочница", + "workspace.create.failed.title": "Не удалось создать рабочее пространство", + "workspace.delete.failed.title": "Не удалось удалить рабочее пространство", + "workspace.resetting.title": "Сброс рабочего пространства", + "workspace.resetting.description": "Это может занять минуту.", + "workspace.reset.failed.title": "Не удалось сбросить рабочее пространство", + "workspace.reset.success.title": "Рабочее пространство сброшено", + "workspace.reset.success.description": "Рабочее пространство теперь соответствует ветке по умолчанию.", + "workspace.status.checking": "Проверка наличия неслитых изменений...", + "workspace.status.error": "Не удалось проверить статус git.", + "workspace.status.clean": "Неслитые изменения не обнаружены.", + "workspace.status.dirty": "Обнаружены неслитые изменения в этом рабочем пространстве.", + "workspace.delete.title": "Удалить рабочее пространство", + "workspace.delete.confirm": 'Удалить рабочее пространство "{{name}}"?', + "workspace.delete.button": "Удалить рабочее пространство", + "workspace.reset.title": "Сбросить рабочее пространство", + "workspace.reset.confirm": 'Сбросить рабочее пространство "{{name}}"?', + "workspace.reset.button": "Сбросить рабочее пространство", + "workspace.reset.archived.none": "Никакие активные сессии не будут архивированы.", + "workspace.reset.archived.one": "1 сессия будет архивирована.", + "workspace.reset.archived.many": "{{count}} сессий будет архивировано.", + "workspace.reset.note": "Рабочее пространство будет сброшено в соответствие с веткой по умолчанию.", +} diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts new file mode 100644 index 00000000000..079c96baafb --- /dev/null +++ b/packages/app/src/i18n/zh.ts @@ -0,0 +1,572 @@ +import { dict as en } from "./en" + +type Keys = keyof typeof en + +export const dict = { + "command.category.suggested": "建议", + "command.category.view": "视图", + "command.category.project": "项目", + "command.category.provider": "提供商", + "command.category.server": "服务器", + "command.category.session": "会话", + "command.category.theme": "主题", + "command.category.language": "语言", + "command.category.file": "文件", + "command.category.terminal": "终端", + "command.category.model": "模型", + "command.category.mcp": "MCP", + "command.category.agent": "智能体", + "command.category.permissions": "权限", + "command.category.workspace": "工作区", + + "theme.scheme.system": "系统", + "theme.scheme.light": "浅色", + "theme.scheme.dark": "深色", + + "command.sidebar.toggle": "切换侧边栏", + "command.project.open": "打开项目", + "command.provider.connect": "连接提供商", + "command.server.switch": "切换服务器", + "command.session.previous": "上一个会话", + "command.session.next": "下一个会话", + "command.session.archive": "归档会话", + + "command.palette": "命令面板", + + "command.theme.cycle": "切换主题", + "command.theme.set": "使用主题: {{theme}}", + "command.theme.scheme.cycle": "切换配色方案", + "command.theme.scheme.set": "使用配色方案: {{scheme}}", + + "command.language.cycle": "切换语言", + "command.language.set": "使用语言: {{language}}", + + "command.session.new": "新建会话", + "command.file.open": "打开文件", + "command.file.open.description": "搜索文件和命令", + "command.terminal.toggle": "切换终端", + "command.review.toggle": "切换审查", + "command.terminal.new": "新建终端", + "command.terminal.new.description": "创建新的终端标签页", + "command.steps.toggle": "切换步骤", + "command.steps.toggle.description": "显示或隐藏当前消息的步骤", + "command.message.previous": "上一条消息", + "command.message.previous.description": "跳转到上一条用户消息", + "command.message.next": "下一条消息", + "command.message.next.description": "跳转到下一条用户消息", + "command.model.choose": "选择模型", + "command.model.choose.description": "选择不同的模型", + "command.mcp.toggle": "切换 MCPs", + "command.mcp.toggle.description": "切换 MCPs", + "command.agent.cycle": "切换智能体", + "command.agent.cycle.description": "切换到下一个智能体", + "command.agent.cycle.reverse": "反向切换智能体", + "command.agent.cycle.reverse.description": "切换到上一个智能体", + "command.model.variant.cycle": "切换思考强度", + "command.model.variant.cycle.description": "切换到下一个强度等级", + "command.permissions.autoaccept.enable": "自动接受编辑", + "command.permissions.autoaccept.disable": "停止自动接受编辑", + "command.session.undo": "撤销", + "command.session.undo.description": "撤销上一条消息", + "command.session.redo": "重做", + "command.session.redo.description": "重做上一条撤销的消息", + "command.session.compact": "精简会话", + "command.session.compact.description": "总结会话以减少上下文大小", + "command.session.fork": "从消息分叉", + "command.session.fork.description": "从之前的消息创建新会话", + "command.session.share": "分享会话", + "command.session.share.description": "分享此会话并将链接复制到剪贴板", + "command.session.unshare": "取消分享会话", + "command.session.unshare.description": "停止分享此会话", + + "palette.search.placeholder": "搜索文件和命令", + "palette.empty": "未找到结果", + "palette.group.commands": "命令", + "palette.group.files": "文件", + + "dialog.provider.search.placeholder": "搜索提供商", + "dialog.provider.empty": "未找到提供商", + "dialog.provider.group.popular": "热门", + "dialog.provider.group.other": "其他", + "dialog.provider.tag.recommended": "推荐", + "dialog.provider.anthropic.note": "使用 Claude Pro/Max 或 API 密钥连接", + + "dialog.model.select.title": "选择模型", + "dialog.model.search.placeholder": "搜索模型", + "dialog.model.empty": "未找到模型", + "dialog.model.manage": "管理模型", + "dialog.model.manage.description": "自定义模型选择器中显示的模型。", + + "dialog.model.unpaid.freeModels.title": "OpenCode 提供的免费模型", + "dialog.model.unpaid.addMore.title": "从热门提供商添加更多模型", + + "dialog.provider.viewAll": "查看全部提供商", + + "provider.connect.title": "连接 {{provider}}", + "provider.connect.title.anthropicProMax": "使用 Claude Pro/Max 登录", + "provider.connect.selectMethod": "选择 {{provider}} 的登录方式。", + "provider.connect.method.apiKey": "API 密钥", + "provider.connect.status.inProgress": "正在授权...", + "provider.connect.status.waiting": "等待授权...", + "provider.connect.status.failed": "授权失败: {{error}}", + "provider.connect.apiKey.description": + "输入你的 {{provider}} API 密钥以连接帐户,并在 OpenCode 中使用 {{provider}} 模型。", + "provider.connect.apiKey.label": "{{provider}} API 密钥", + "provider.connect.apiKey.placeholder": "API 密钥", + "provider.connect.apiKey.required": "API 密钥为必填项", + "provider.connect.opencodeZen.line1": "OpenCode Zen 为你提供一组精选的可靠优化模型,用于代码智能体。", + "provider.connect.opencodeZen.line2": "只需一个 API 密钥,你就能使用 Claude、GPT、Gemini、GLM 等模型。", + "provider.connect.opencodeZen.visit.prefix": "访问 ", + "provider.connect.opencodeZen.visit.suffix": " 获取你的 API 密钥。", + "provider.connect.oauth.code.visit.prefix": "访问 ", + "provider.connect.oauth.code.visit.link": "此链接", + "provider.connect.oauth.code.visit.suffix": " 获取授权码,以连接你的帐户并在 OpenCode 中使用 {{provider}} 模型。", + "provider.connect.oauth.code.label": "{{method}} 授权码", + "provider.connect.oauth.code.placeholder": "授权码", + "provider.connect.oauth.code.required": "授权码为必填项", + "provider.connect.oauth.code.invalid": "授权码无效", + "provider.connect.oauth.auto.visit.prefix": "访问 ", + "provider.connect.oauth.auto.visit.link": "此链接", + "provider.connect.oauth.auto.visit.suffix": " 并输入以下代码,以连接你的帐户并在 OpenCode 中使用 {{provider}} 模型。", + "provider.connect.oauth.auto.confirmationCode": "确认码", + "provider.connect.toast.connected.title": "{{provider}} 已连接", + "provider.connect.toast.connected.description": "现在可以使用 {{provider}} 模型了。", + + "model.tag.free": "免费", + "model.tag.latest": "最新", + + "common.search.placeholder": "搜索", + "common.goBack": "返回", + "common.loading": "加载中", + "common.cancel": "取消", + "common.submit": "提交", + "common.save": "保存", + "common.saving": "保存中...", + "common.default": "默认", + "common.attachment": "附件", + + "prompt.placeholder.shell": "输入 shell 命令...", + "prompt.placeholder.normal": '随便问点什么... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "按 esc 退出", + + "prompt.example.1": "修复代码库中的一个 TODO", + "prompt.example.2": "这个项目的技术栈是什么?", + "prompt.example.3": "修复失败的测试", + "prompt.example.4": "解释认证是如何工作的", + "prompt.example.5": "查找并修复安全漏洞", + "prompt.example.6": "为用户服务添加单元测试", + "prompt.example.7": "重构这个函数,让它更易读", + "prompt.example.8": "这个错误是什么意思?", + "prompt.example.9": "帮我调试这个问题", + "prompt.example.10": "生成 API 文档", + "prompt.example.11": "优化数据库查询", + "prompt.example.12": "添加输入校验", + "prompt.example.13": "创建一个新的组件用于...", + "prompt.example.14": "我该如何部署这个项目?", + "prompt.example.15": "审查我的代码并给出最佳实践建议", + "prompt.example.16": "为这个函数添加错误处理", + "prompt.example.17": "解释这个正则表达式", + "prompt.example.18": "把它转换成 TypeScript", + "prompt.example.19": "在整个代码库中添加日志", + "prompt.example.20": "哪些依赖已经过期?", + "prompt.example.21": "帮我写一个迁移脚本", + "prompt.example.22": "为这个接口实现缓存", + "prompt.example.23": "给这个列表添加分页", + "prompt.example.24": "创建一个 CLI 命令用于...", + "prompt.example.25": "这里的环境变量是怎么工作的?", + + "prompt.popover.emptyResults": "没有匹配的结果", + "prompt.popover.emptyCommands": "没有匹配的命令", + "prompt.dropzone.label": "将图片或 PDF 拖到这里", + "prompt.slash.badge.custom": "自定义", + "prompt.context.active": "当前", + "prompt.context.includeActiveFile": "包含当前文件", + "prompt.context.removeActiveFile": "从上下文移除活动文件", + "prompt.context.removeFile": "从上下文移除文件", + "prompt.action.attachFile": "附加文件", + "prompt.attachment.remove": "移除附件", + "prompt.action.send": "发送", + "prompt.action.stop": "停止", + + "prompt.toast.pasteUnsupported.title": "不支持的粘贴", + "prompt.toast.pasteUnsupported.description": "这里只能粘贴图片或 PDF 文件。", + "prompt.toast.modelAgentRequired.title": "请选择智能体和模型", + "prompt.toast.modelAgentRequired.description": "发送提示前请先选择智能体和模型。", + "prompt.toast.worktreeCreateFailed.title": "创建工作树失败", + "prompt.toast.sessionCreateFailed.title": "创建会话失败", + "prompt.toast.shellSendFailed.title": "发送 shell 命令失败", + "prompt.toast.commandSendFailed.title": "发送命令失败", + "prompt.toast.promptSendFailed.title": "发送提示失败", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "已启用 {{enabled}} / {{total}}", + "dialog.mcp.empty": "未配置 MCPs", + + "mcp.status.connected": "已连接", + "mcp.status.failed": "失败", + "mcp.status.needs_auth": "需要授权", + "mcp.status.disabled": "已禁用", + + "dialog.fork.empty": "没有可用于分叉的消息", + + "dialog.directory.search.placeholder": "搜索文件夹", + "dialog.directory.empty": "未找到文件夹", + + "dialog.server.title": "服务器", + "dialog.server.description": "切换此应用连接的 OpenCode 服务器。", + "dialog.server.search.placeholder": "搜索服务器", + "dialog.server.empty": "暂无服务器", + "dialog.server.add.title": "添加服务器", + "dialog.server.add.url": "服务器 URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "无法连接到服务器", + "dialog.server.add.checking": "检查中...", + "dialog.server.add.button": "添加", + "dialog.server.default.title": "默认服务器", + "dialog.server.default.description": "应用启动时连接此服务器,而不是启动本地服务器。需要重启。", + "dialog.server.default.none": "未选择服务器", + "dialog.server.default.set": "将当前服务器设为默认", + "dialog.server.default.clear": "清除", + "dialog.server.action.remove": "移除服务器", + + "dialog.project.edit.title": "编辑项目", + "dialog.project.edit.name": "名称", + "dialog.project.edit.icon": "图标", + "dialog.project.edit.icon.alt": "项目图标", + "dialog.project.edit.icon.hint": "点击或拖拽图片", + "dialog.project.edit.icon.recommended": "建议:128x128px", + "dialog.project.edit.color": "颜色", + "dialog.project.edit.color.select": "选择{{color}}颜色", + + "context.breakdown.title": "上下文拆分", + "context.breakdown.note": "输入 token 的大致拆分。“其他”包含工具定义和开销。", + "context.breakdown.system": "系统", + "context.breakdown.user": "用户", + "context.breakdown.assistant": "助手", + "context.breakdown.tool": "工具调用", + "context.breakdown.other": "其他", + + "context.systemPrompt.title": "系统提示词", + "context.rawMessages.title": "原始消息", + + "context.stats.session": "会话", + "context.stats.messages": "消息数", + "context.stats.provider": "提供商", + "context.stats.model": "模型", + "context.stats.limit": "上下文限制", + "context.stats.totalTokens": "总 token", + "context.stats.usage": "使用率", + "context.stats.inputTokens": "输入 token", + "context.stats.outputTokens": "输出 token", + "context.stats.reasoningTokens": "推理 token", + "context.stats.cacheTokens": "缓存 token(读/写)", + "context.stats.userMessages": "用户消息", + "context.stats.assistantMessages": "助手消息", + "context.stats.totalCost": "总成本", + "context.stats.sessionCreated": "创建时间", + "context.stats.lastActivity": "最后活动", + + "context.usage.tokens": "Token", + "context.usage.usage": "使用率", + "context.usage.cost": "成本", + "context.usage.clickToView": "点击查看上下文", + "context.usage.view": "查看上下文用量", + + "language.en": "英语", + "language.zh": "简体中文", + "language.zht": "繁体中文", + "language.ko": "韩语", + "language.de": "德语", + "language.es": "西班牙语", + "language.fr": "法语", + "language.ja": "日语", + "language.da": "丹麦语", + "language.ru": "俄语", + "language.pl": "波兰语", + "language.ar": "阿拉伯语", + "language.no": "挪威语", + "language.br": "葡萄牙语(巴西)", + + "toast.language.title": "语言", + "toast.language.description": "已切换到{{language}}", + + "toast.theme.title": "主题已切换", + "toast.scheme.title": "配色方案", + + "toast.permissions.autoaccept.on.title": "自动接受编辑", + "toast.permissions.autoaccept.on.description": "编辑和写入权限将自动获批", + "toast.permissions.autoaccept.off.title": "已停止自动接受编辑", + "toast.permissions.autoaccept.off.description": "编辑和写入权限将需要手动批准", + + "toast.model.none.title": "未选择模型", + "toast.model.none.description": "请先连接提供商以总结此会话", + + "toast.file.loadFailed.title": "加载文件失败", + + "toast.session.share.copyFailed.title": "无法复制链接到剪贴板", + "toast.session.share.success.title": "会话已分享", + "toast.session.share.success.description": "分享链接已复制到剪贴板", + "toast.session.share.failed.title": "分享会话失败", + "toast.session.share.failed.description": "分享会话时发生错误", + + "toast.session.unshare.success.title": "已取消分享会话", + "toast.session.unshare.success.description": "会话已成功取消分享", + "toast.session.unshare.failed.title": "取消分享失败", + "toast.session.unshare.failed.description": "取消分享会话时发生错误", + + "toast.session.listFailed.title": "无法加载 {{project}} 的会话", + + "toast.update.title": "有可用更新", + "toast.update.description": "OpenCode 有新版本 ({{version}}) 可安装。", + "toast.update.action.installRestart": "安装并重启", + "toast.update.action.notYet": "稍后", + + "error.page.title": "出了点问题", + "error.page.description": "加载应用程序时发生错误。", + "error.page.details.label": "错误详情", + "error.page.action.restart": "重启", + "error.page.action.checking": "检查中...", + "error.page.action.checkUpdates": "检查更新", + "error.page.action.updateTo": "更新到 {{version}}", + "error.page.report.prefix": "请将此错误报告给 OpenCode 团队", + "error.page.report.discord": "在 Discord 上", + "error.page.version": "版本: {{version}}", + + "error.dev.rootNotFound": "未找到根元素。你是不是忘了把它添加到 index.html? 或者 id 属性拼写错了?", + + "error.globalSync.connectFailed": "无法连接到服务器。是否有服务器正在 `{{url}}` 运行?", + + "error.chain.unknown": "未知错误", + "error.chain.causedBy": "原因:", + "error.chain.apiError": "API 错误", + "error.chain.status": "状态: {{status}}", + "error.chain.retryable": "可重试: {{retryable}}", + "error.chain.responseBody": "响应内容:\n{{body}}", + "error.chain.didYouMean": "你是不是想输入: {{suggestions}}", + "error.chain.modelNotFound": "未找到模型: {{provider}}/{{model}}", + "error.chain.checkConfig": "请检查你的配置 (opencode.json) 中的 provider/model 名称", + "error.chain.mcpFailed": 'MCP 服务器 "{{name}}" 启动失败。注意: OpenCode 暂不支持 MCP 认证。', + "error.chain.providerAuthFailed": "提供商认证失败 ({{provider}}): {{message}}", + "error.chain.providerInitFailed": '无法初始化提供商 "{{provider}}"。请检查凭据和配置。', + "error.chain.configJsonInvalid": "配置文件 {{path}} 不是有效的 JSON(C)", + "error.chain.configJsonInvalidWithMessage": "配置文件 {{path}} 不是有效的 JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + '{{path}} 中的目录 "{{dir}}" 无效。请将目录重命名为 "{{suggestion}}" 或移除它。这是一个常见拼写错误。', + "error.chain.configFrontmatterError": "无法解析 {{path}} 中的 frontmatter:\n{{message}}", + "error.chain.configInvalid": "配置文件 {{path}} 无效", + "error.chain.configInvalidWithMessage": "配置文件 {{path}} 无效: {{message}}", + + "notification.permission.title": "需要权限", + "notification.permission.description": "{{sessionTitle}}({{projectName}})需要权限", + "notification.question.title": "问题", + "notification.question.description": "{{sessionTitle}}({{projectName}})有一个问题", + "notification.action.goToSession": "前往会话", + + "notification.session.responseReady.title": "回复已就绪", + "notification.session.error.title": "会话错误", + "notification.session.error.fallbackDescription": "发生错误", + + "home.recentProjects": "最近项目", + "home.empty.title": "没有最近项目", + "home.empty.description": "通过打开本地项目开始使用", + + "session.tab.session": "会话", + "session.tab.review": "审查", + "session.tab.context": "上下文", + "session.panel.reviewAndFiles": "审查和文件", + "session.review.filesChanged": "{{count}} 个文件变更", + "session.review.loadingChanges": "正在加载更改...", + "session.review.empty": "此会话暂无更改", + "session.messages.renderEarlier": "显示更早的消息", + "session.messages.loadingEarlier": "正在加载更早的消息...", + "session.messages.loadEarlier": "加载更早的消息", + "session.messages.loading": "正在加载消息...", + + "session.context.addToContext": "将 {{selection}} 添加到上下文", + + "session.new.worktree.main": "主分支", + "session.new.worktree.mainWithBranch": "主分支 ({{branch}})", + "session.new.worktree.create": "创建新的 worktree", + "session.new.lastModified": "最后修改", + + "session.header.search.placeholder": "搜索 {{project}}", + "session.header.searchFiles": "搜索文件", + + "session.share.popover.title": "发布到网页", + "session.share.popover.description.shared": "此会话已在网页上公开。任何拥有链接的人都可以访问。", + "session.share.popover.description.unshared": "在网页上公开分享此会话。任何拥有链接的人都可以访问。", + "session.share.action.share": "分享", + "session.share.action.publish": "发布", + "session.share.action.publishing": "正在发布...", + "session.share.action.unpublish": "取消发布", + "session.share.action.unpublishing": "正在取消发布...", + "session.share.action.view": "查看", + "session.share.copy.copied": "已复制", + "session.share.copy.copyLink": "复制链接", + + "lsp.tooltip.none": "没有 LSP 服务器", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "正在加载提示...", + "terminal.loading": "正在加载终端...", + "terminal.title": "终端", + "terminal.title.numbered": "终端 {{number}}", + "terminal.close": "关闭终端", + + "common.closeTab": "关闭标签页", + "common.dismiss": "忽略", + "common.requestFailed": "请求失败", + "common.moreOptions": "更多选项", + "common.learnMore": "了解更多", + "common.rename": "重命名", + "common.reset": "重置", + "common.archive": "归档", + "common.delete": "删除", + "common.close": "关闭", + "common.edit": "编辑", + "common.loadMore": "加载更多", + + "sidebar.nav.projectsAndSessions": "项目和会话", + "sidebar.settings": "设置", + "sidebar.help": "帮助", + "sidebar.workspaces.enable": "启用工作区", + "sidebar.workspaces.disable": "禁用工作区", + "sidebar.gettingStarted.title": "入门", + "sidebar.gettingStarted.line1": "OpenCode 提供免费模型,你可以立即开始使用。", + "sidebar.gettingStarted.line2": "连接任意提供商即可使用更多模型,如 Claude、GPT、Gemini 等。", + "sidebar.project.recentSessions": "最近会话", + "sidebar.project.viewAllSessions": "查看全部会话", + + "settings.section.desktop": "桌面", + "settings.tab.general": "通用", + "settings.tab.shortcuts": "快捷键", + + "settings.general.section.appearance": "外观", + "settings.general.section.notifications": "系统通知", + "settings.general.section.sounds": "音效", + + "settings.general.row.language.title": "语言", + "settings.general.row.language.description": "更改 OpenCode 的显示语言", + "settings.general.row.appearance.title": "外观", + "settings.general.row.appearance.description": "自定义 OpenCode 在你的设备上的外观", + "settings.general.row.theme.title": "主题", + "settings.general.row.theme.description": "自定义 OpenCode 的主题。", + "settings.general.row.font.title": "字体", + "settings.general.row.font.description": "自定义代码块使用的等宽字体", + + "settings.general.notifications.agent.title": "智能体", + "settings.general.notifications.agent.description": "当智能体完成或需要注意时显示系统通知", + "settings.general.notifications.permissions.title": "权限", + "settings.general.notifications.permissions.description": "当需要权限时显示系统通知", + "settings.general.notifications.errors.title": "错误", + "settings.general.notifications.errors.description": "发生错误时显示系统通知", + + "settings.general.sounds.agent.title": "智能体", + "settings.general.sounds.agent.description": "当智能体完成或需要注意时播放声音", + "settings.general.sounds.permissions.title": "权限", + "settings.general.sounds.permissions.description": "当需要权限时播放声音", + "settings.general.sounds.errors.title": "错误", + "settings.general.sounds.errors.description": "发生错误时播放声音", + + "settings.shortcuts.title": "键盘快捷键", + "settings.shortcuts.reset.button": "重置为默认值", + "settings.shortcuts.reset.toast.title": "快捷键已重置", + "settings.shortcuts.reset.toast.description": "键盘快捷键已重置为默认设置。", + "settings.shortcuts.conflict.title": "快捷键已被占用", + "settings.shortcuts.conflict.description": "{{keybind}} 已分配给 {{titles}}。", + "settings.shortcuts.unassigned": "未设置", + "settings.shortcuts.pressKeys": "按下按键", + "settings.shortcuts.search.placeholder": "搜索快捷键", + "settings.shortcuts.search.empty": "未找到快捷键", + + "settings.shortcuts.group.general": "通用", + "settings.shortcuts.group.session": "会话", + "settings.shortcuts.group.navigation": "导航", + "settings.shortcuts.group.modelAndAgent": "模型与智能体", + "settings.shortcuts.group.terminal": "终端", + "settings.shortcuts.group.prompt": "提示", + + "settings.providers.title": "提供商", + "settings.providers.description": "提供商设置将在此处可配置。", + "settings.models.title": "模型", + "settings.models.description": "模型设置将在此处可配置。", + "settings.agents.title": "智能体", + "settings.agents.description": "智能体设置将在此处可配置。", + "settings.commands.title": "命令", + "settings.commands.description": "命令设置将在此处可配置。", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP 设置将在此处可配置。", + + "settings.permissions.title": "权限", + "settings.permissions.description": "控制服务器默认可以使用哪些工具。", + "settings.permissions.section.tools": "工具", + "settings.permissions.toast.updateFailed.title": "更新权限失败", + + "settings.permissions.action.allow": "允许", + "settings.permissions.action.ask": "询问", + "settings.permissions.action.deny": "拒绝", + + "settings.permissions.tool.read.title": "读取", + "settings.permissions.tool.read.description": "读取文件(匹配文件路径)", + "settings.permissions.tool.edit.title": "编辑", + "settings.permissions.tool.edit.description": "修改文件,包括编辑、写入、补丁和多重编辑", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "使用 glob 模式匹配文件", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "使用正则表达式搜索文件内容", + "settings.permissions.tool.list.title": "列表", + "settings.permissions.tool.list.description": "列出目录中的文件", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "运行 shell 命令", + "settings.permissions.tool.task.title": "Task", + "settings.permissions.tool.task.description": "启动子智能体", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "按名称加载技能", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "运行语言服务器查询", + "settings.permissions.tool.todoread.title": "读取待办", + "settings.permissions.tool.todoread.description": "读取待办列表", + "settings.permissions.tool.todowrite.title": "更新待办", + "settings.permissions.tool.todowrite.description": "更新待办列表", + "settings.permissions.tool.webfetch.title": "Web Fetch", + "settings.permissions.tool.webfetch.description": "从 URL 获取内容", + "settings.permissions.tool.websearch.title": "Web Search", + "settings.permissions.tool.websearch.description": "搜索网页", + "settings.permissions.tool.codesearch.title": "Code Search", + "settings.permissions.tool.codesearch.description": "在网上搜索代码", + "settings.permissions.tool.external_directory.title": "外部目录", + "settings.permissions.tool.external_directory.description": "访问项目目录之外的文件", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "检测具有相同输入的重复工具调用", + + "session.delete.failed.title": "删除会话失败", + "session.delete.title": "删除会话", + "session.delete.confirm": '删除会话 "{{name}}"?', + "session.delete.button": "删除会话", + + "workspace.new": "新建工作区", + "workspace.type.local": "本地", + "workspace.type.sandbox": "沙盒", + "workspace.create.failed.title": "创建工作区失败", + "workspace.delete.failed.title": "删除工作区失败", + "workspace.resetting.title": "正在重置工作区", + "workspace.resetting.description": "这可能需要一点时间。", + "workspace.reset.failed.title": "重置工作区失败", + "workspace.reset.success.title": "工作区已重置", + "workspace.reset.success.description": "工作区已与默认分支保持一致。", + "workspace.status.checking": "正在检查未合并的更改...", + "workspace.status.error": "无法验证 git 状态。", + "workspace.status.clean": "未检测到未合并的更改。", + "workspace.status.dirty": "检测到未合并的更改。", + "workspace.delete.title": "删除工作区", + "workspace.delete.confirm": '删除工作区 "{{name}}"?', + "workspace.delete.button": "删除工作区", + "workspace.reset.title": "重置工作区", + "workspace.reset.confirm": '重置工作区 "{{name}}"?', + "workspace.reset.button": "重置工作区", + "workspace.reset.archived.none": "不会归档任何活跃会话。", + "workspace.reset.archived.one": "将归档 1 个会话。", + "workspace.reset.archived.many": "将归档 {{count}} 个会话。", + "workspace.reset.note": "这将把工作区重置为与默认分支一致。", +} satisfies Partial> diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts new file mode 100644 index 00000000000..35b25dd1dc2 --- /dev/null +++ b/packages/app/src/i18n/zht.ts @@ -0,0 +1,568 @@ +import { dict as en } from "./en" + +type Keys = keyof typeof en + +export const dict = { + "command.category.suggested": "建議", + "command.category.view": "檢視", + "command.category.project": "專案", + "command.category.provider": "提供者", + "command.category.server": "伺服器", + "command.category.session": "工作階段", + "command.category.theme": "主題", + "command.category.language": "語言", + "command.category.file": "檔案", + "command.category.terminal": "終端機", + "command.category.model": "模型", + "command.category.mcp": "MCP", + "command.category.agent": "代理程式", + "command.category.permissions": "權限", + "command.category.workspace": "工作區", + + "theme.scheme.system": "系統", + "theme.scheme.light": "淺色", + "theme.scheme.dark": "深色", + + "command.sidebar.toggle": "切換側邊欄", + "command.project.open": "開啟專案", + "command.provider.connect": "連接提供者", + "command.server.switch": "切換伺服器", + "command.session.previous": "上一個工作階段", + "command.session.next": "下一個工作階段", + "command.session.archive": "封存工作階段", + + "command.palette": "命令面板", + + "command.theme.cycle": "循環主題", + "command.theme.set": "使用主題: {{theme}}", + "command.theme.scheme.cycle": "循環配色方案", + "command.theme.scheme.set": "使用配色方案: {{scheme}}", + + "command.language.cycle": "循環語言", + "command.language.set": "使用語言: {{language}}", + + "command.session.new": "新增工作階段", + "command.file.open": "開啟檔案", + "command.file.open.description": "搜尋檔案和命令", + "command.terminal.toggle": "切換終端機", + "command.review.toggle": "切換審查", + "command.terminal.new": "新增終端機", + "command.terminal.new.description": "建立新的終端機標籤頁", + "command.steps.toggle": "切換步驟", + "command.steps.toggle.description": "顯示或隱藏目前訊息的步驟", + "command.message.previous": "上一則訊息", + "command.message.previous.description": "跳到上一則使用者訊息", + "command.message.next": "下一則訊息", + "command.message.next.description": "跳到下一則使用者訊息", + "command.model.choose": "選擇模型", + "command.model.choose.description": "選擇不同的模型", + "command.mcp.toggle": "切換 MCP", + "command.mcp.toggle.description": "切換 MCP", + "command.agent.cycle": "循環代理程式", + "command.agent.cycle.description": "切換到下一個代理程式", + "command.agent.cycle.reverse": "反向循環代理程式", + "command.agent.cycle.reverse.description": "切換到上一個代理程式", + "command.model.variant.cycle": "循環思考強度", + "command.model.variant.cycle.description": "切換到下一個強度等級", + "command.permissions.autoaccept.enable": "自動接受編輯", + "command.permissions.autoaccept.disable": "停止自動接受編輯", + "command.session.undo": "復原", + "command.session.undo.description": "復原上一則訊息", + "command.session.redo": "重做", + "command.session.redo.description": "重做上一則復原的訊息", + "command.session.compact": "精簡工作階段", + "command.session.compact.description": "總結工作階段以減少上下文大小", + "command.session.fork": "從訊息分支", + "command.session.fork.description": "從先前的訊息建立新工作階段", + "command.session.share": "分享工作階段", + "command.session.share.description": "分享此工作階段並將連結複製到剪貼簿", + "command.session.unshare": "取消分享工作階段", + "command.session.unshare.description": "停止分享此工作階段", + + "palette.search.placeholder": "搜尋檔案和命令", + "palette.empty": "找不到結果", + "palette.group.commands": "命令", + "palette.group.files": "檔案", + + "dialog.provider.search.placeholder": "搜尋提供者", + "dialog.provider.empty": "找不到提供者", + "dialog.provider.group.popular": "熱門", + "dialog.provider.group.other": "其他", + "dialog.provider.tag.recommended": "推薦", + "dialog.provider.anthropic.note": "使用 Claude Pro/Max 或 API 金鑰連線", + + "dialog.model.select.title": "選擇模型", + "dialog.model.search.placeholder": "搜尋模型", + "dialog.model.empty": "找不到模型", + "dialog.model.manage": "管理模型", + "dialog.model.manage.description": "自訂模型選擇器中顯示的模型。", + + "dialog.model.unpaid.freeModels.title": "OpenCode 提供的免費模型", + "dialog.model.unpaid.addMore.title": "從熱門提供者新增更多模型", + + "dialog.provider.viewAll": "查看全部提供者", + + "provider.connect.title": "連線 {{provider}}", + "provider.connect.title.anthropicProMax": "使用 Claude Pro/Max 登入", + "provider.connect.selectMethod": "選擇 {{provider}} 的登入方式。", + "provider.connect.method.apiKey": "API 金鑰", + "provider.connect.status.inProgress": "正在授權...", + "provider.connect.status.waiting": "等待授權...", + "provider.connect.status.failed": "授權失敗: {{error}}", + "provider.connect.apiKey.description": + "輸入你的 {{provider}} API 金鑰以連線帳戶,並在 OpenCode 中使用 {{provider}} 模型。", + "provider.connect.apiKey.label": "{{provider}} API 金鑰", + "provider.connect.apiKey.placeholder": "API 金鑰", + "provider.connect.apiKey.required": "API 金鑰為必填", + "provider.connect.opencodeZen.line1": "OpenCode Zen 為你提供一組精選的可靠最佳化模型,用於程式碼代理程式。", + "provider.connect.opencodeZen.line2": "只需一個 API 金鑰,你就能使用 Claude、GPT、Gemini、GLM 等模型。", + "provider.connect.opencodeZen.visit.prefix": "造訪 ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " 取得你的 API 金鑰。", + "provider.connect.oauth.code.visit.prefix": "造訪 ", + "provider.connect.oauth.code.visit.link": "此連結", + "provider.connect.oauth.code.visit.suffix": " 取得授權碼,以連線你的帳戶並在 OpenCode 中使用 {{provider}} 模型。", + "provider.connect.oauth.code.label": "{{method}} 授權碼", + "provider.connect.oauth.code.placeholder": "授權碼", + "provider.connect.oauth.code.required": "授權碼為必填", + "provider.connect.oauth.code.invalid": "授權碼無效", + "provider.connect.oauth.auto.visit.prefix": "造訪 ", + "provider.connect.oauth.auto.visit.link": "此連結", + "provider.connect.oauth.auto.visit.suffix": + " 並輸入以下程式碼,以連線你的帳戶並在 OpenCode 中使用 {{provider}} 模型。", + "provider.connect.oauth.auto.confirmationCode": "確認碼", + "provider.connect.toast.connected.title": "{{provider}} 已連線", + "provider.connect.toast.connected.description": "現在可以使用 {{provider}} 模型了。", + + "model.tag.free": "免費", + "model.tag.latest": "最新", + + "common.search.placeholder": "搜尋", + "common.goBack": "返回", + "common.loading": "載入中", + "common.cancel": "取消", + "common.submit": "提交", + "common.save": "儲存", + "common.saving": "儲存中...", + "common.default": "預設", + "common.attachment": "附件", + + "prompt.placeholder.shell": "輸入 shell 命令...", + "prompt.placeholder.normal": '隨便問點什麼... "{{example}}"', + "prompt.mode.shell": "Shell", + "prompt.mode.shell.exit": "按 esc 退出", + + "prompt.example.1": "修復程式碼庫中的一個 TODO", + "prompt.example.2": "這個專案的技術堆疊是什麼?", + "prompt.example.3": "修復失敗的測試", + "prompt.example.4": "解釋驗證是如何運作的", + "prompt.example.5": "尋找並修復安全漏洞", + "prompt.example.6": "為使用者服務新增單元測試", + "prompt.example.7": "重構這個函式,讓它更易讀", + "prompt.example.8": "這個錯誤是什麼意思?", + "prompt.example.9": "幫我偵錯這個問題", + "prompt.example.10": "產生 API 文件", + "prompt.example.11": "最佳化資料庫查詢", + "prompt.example.12": "新增輸入驗證", + "prompt.example.13": "建立一個新的元件用於...", + "prompt.example.14": "我該如何部署這個專案?", + "prompt.example.15": "審查我的程式碼並給出最佳實務建議", + "prompt.example.16": "為這個函式新增錯誤處理", + "prompt.example.17": "解釋這個正規表示式", + "prompt.example.18": "把它轉換成 TypeScript", + "prompt.example.19": "在整個程式碼庫中新增日誌", + "prompt.example.20": "哪些相依性已經過期?", + "prompt.example.21": "幫我寫一個遷移腳本", + "prompt.example.22": "為這個端點實作快取", + "prompt.example.23": "給這個清單新增分頁", + "prompt.example.24": "建立一個 CLI 命令用於...", + "prompt.example.25": "這裡的環境變數是怎麼運作的?", + + "prompt.popover.emptyResults": "沒有符合的結果", + "prompt.popover.emptyCommands": "沒有符合的命令", + "prompt.dropzone.label": "將圖片或 PDF 拖到這裡", + "prompt.slash.badge.custom": "自訂", + "prompt.context.active": "作用中", + "prompt.context.includeActiveFile": "包含作用中檔案", + "prompt.context.removeActiveFile": "從上下文移除目前檔案", + "prompt.context.removeFile": "從上下文移除檔案", + "prompt.action.attachFile": "附加檔案", + "prompt.attachment.remove": "移除附件", + "prompt.action.send": "傳送", + "prompt.action.stop": "停止", + + "prompt.toast.pasteUnsupported.title": "不支援的貼上", + "prompt.toast.pasteUnsupported.description": "這裡只能貼上圖片或 PDF 檔案。", + "prompt.toast.modelAgentRequired.title": "請選擇代理程式和模型", + "prompt.toast.modelAgentRequired.description": "傳送提示前請先選擇代理程式和模型。", + "prompt.toast.worktreeCreateFailed.title": "建立工作樹失敗", + "prompt.toast.sessionCreateFailed.title": "建立工作階段失敗", + "prompt.toast.shellSendFailed.title": "傳送 shell 命令失敗", + "prompt.toast.commandSendFailed.title": "傳送命令失敗", + "prompt.toast.promptSendFailed.title": "傳送提示失敗", + + "dialog.mcp.title": "MCP", + "dialog.mcp.description": "已啟用 {{enabled}} / {{total}}", + "dialog.mcp.empty": "未設定 MCP", + + "mcp.status.connected": "已連線", + "mcp.status.failed": "失敗", + "mcp.status.needs_auth": "需要授權", + "mcp.status.disabled": "已停用", + + "dialog.fork.empty": "沒有可用於分支的訊息", + + "dialog.directory.search.placeholder": "搜尋資料夾", + "dialog.directory.empty": "找不到資料夾", + + "dialog.server.title": "伺服器", + "dialog.server.description": "切換此應用程式連線的 OpenCode 伺服器。", + "dialog.server.search.placeholder": "搜尋伺服器", + "dialog.server.empty": "暫無伺服器", + "dialog.server.add.title": "新增伺服器", + "dialog.server.add.url": "伺服器 URL", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "無法連線到伺服器", + "dialog.server.add.checking": "檢查中...", + "dialog.server.add.button": "新增", + "dialog.server.default.title": "預設伺服器", + "dialog.server.default.description": "應用程式啟動時連線此伺服器,而不是啟動本地伺服器。需要重新啟動。", + "dialog.server.default.none": "未選擇伺服器", + "dialog.server.default.set": "將目前伺服器設為預設", + "dialog.server.default.clear": "清除", + "dialog.server.action.remove": "移除伺服器", + + "dialog.project.edit.title": "編輯專案", + "dialog.project.edit.name": "名稱", + "dialog.project.edit.icon": "圖示", + "dialog.project.edit.icon.alt": "專案圖示", + "dialog.project.edit.icon.hint": "點擊或拖曳圖片", + "dialog.project.edit.icon.recommended": "建議:128x128px", + "dialog.project.edit.color": "顏色", + "dialog.project.edit.color.select": "選擇{{color}}顏色", + + "context.breakdown.title": "上下文拆分", + "context.breakdown.note": "輸入 token 的大致拆分。「其他」包含工具定義和額外開銷。", + "context.breakdown.system": "系統", + "context.breakdown.user": "使用者", + "context.breakdown.assistant": "助手", + "context.breakdown.tool": "工具呼叫", + "context.breakdown.other": "其他", + + "context.systemPrompt.title": "系統提示詞", + "context.rawMessages.title": "原始訊息", + + "context.stats.session": "工作階段", + "context.stats.messages": "訊息數", + "context.stats.provider": "提供者", + "context.stats.model": "模型", + "context.stats.limit": "上下文限制", + "context.stats.totalTokens": "總 token", + "context.stats.usage": "使用量", + "context.stats.inputTokens": "輸入 token", + "context.stats.outputTokens": "輸出 token", + "context.stats.reasoningTokens": "推理 token", + "context.stats.cacheTokens": "快取 token(讀/寫)", + "context.stats.userMessages": "使用者訊息", + "context.stats.assistantMessages": "助手訊息", + "context.stats.totalCost": "總成本", + "context.stats.sessionCreated": "建立時間", + "context.stats.lastActivity": "最後活動", + + "context.usage.tokens": "Token", + "context.usage.usage": "使用量", + "context.usage.cost": "成本", + "context.usage.clickToView": "點擊查看上下文", + "context.usage.view": "檢視上下文用量", + + "language.en": "英語", + "language.zh": "簡體中文", + "language.zht": "繁體中文", + "language.ko": "韓語", + "language.ru": "俄語", + "language.ar": "阿拉伯語", + "language.no": "挪威語", + "language.br": "葡萄牙語(巴西)", + + "toast.language.title": "語言", + "toast.language.description": "已切換到 {{language}}", + + "toast.theme.title": "主題已切換", + "toast.scheme.title": "配色方案", + + "toast.permissions.autoaccept.on.title": "自動接受編輯", + "toast.permissions.autoaccept.on.description": "編輯和寫入權限將自動獲准", + "toast.permissions.autoaccept.off.title": "已停止自動接受編輯", + "toast.permissions.autoaccept.off.description": "編輯和寫入權限將需要手動批准", + + "toast.model.none.title": "未選擇模型", + "toast.model.none.description": "請先連線提供者以總結此工作階段", + + "toast.file.loadFailed.title": "載入檔案失敗", + + "toast.session.share.copyFailed.title": "無法複製連結到剪貼簿", + "toast.session.share.success.title": "工作階段已分享", + "toast.session.share.success.description": "分享連結已複製到剪貼簿", + "toast.session.share.failed.title": "分享工作階段失敗", + "toast.session.share.failed.description": "分享工作階段時發生錯誤", + + "toast.session.unshare.success.title": "已取消分享工作階段", + "toast.session.unshare.success.description": "工作階段已成功取消分享", + "toast.session.unshare.failed.title": "取消分享失敗", + "toast.session.unshare.failed.description": "取消分享工作階段時發生錯誤", + + "toast.session.listFailed.title": "無法載入 {{project}} 的工作階段", + + "toast.update.title": "有可用更新", + "toast.update.description": "OpenCode 有新版本 ({{version}}) 可安裝。", + "toast.update.action.installRestart": "安裝並重新啟動", + "toast.update.action.notYet": "稍後", + + "error.page.title": "出了點問題", + "error.page.description": "載入應用程式時發生錯誤。", + "error.page.details.label": "錯誤詳情", + "error.page.action.restart": "重新啟動", + "error.page.action.checking": "檢查中...", + "error.page.action.checkUpdates": "檢查更新", + "error.page.action.updateTo": "更新到 {{version}}", + "error.page.report.prefix": "請將此錯誤回報給 OpenCode 團隊", + "error.page.report.discord": "在 Discord 上", + "error.page.version": "版本: {{version}}", + + "error.dev.rootNotFound": "找不到根元素。你是不是忘了把它新增到 index.html? 或者 id 屬性拼錯了?", + + "error.globalSync.connectFailed": "無法連線到伺服器。是否有伺服器正在 `{{url}}` 執行?", + + "error.chain.unknown": "未知錯誤", + "error.chain.causedBy": "原因:", + "error.chain.apiError": "API 錯誤", + "error.chain.status": "狀態: {{status}}", + "error.chain.retryable": "可重試: {{retryable}}", + "error.chain.responseBody": "回應內容:\n{{body}}", + "error.chain.didYouMean": "你是不是想輸入: {{suggestions}}", + "error.chain.modelNotFound": "找不到模型: {{provider}}/{{model}}", + "error.chain.checkConfig": "請檢查你的設定 (opencode.json) 中的 provider/model 名稱", + "error.chain.mcpFailed": 'MCP 伺服器 "{{name}}" 啟動失敗。注意: OpenCode 暫不支援 MCP 認證。', + "error.chain.providerAuthFailed": "提供者認證失敗 ({{provider}}): {{message}}", + "error.chain.providerInitFailed": '無法初始化提供者 "{{provider}}"。請檢查憑證和設定。', + "error.chain.configJsonInvalid": "設定檔 {{path}} 不是有效的 JSON(C)", + "error.chain.configJsonInvalidWithMessage": "設定檔 {{path}} 不是有效的 JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + '{{path}} 中的目錄 "{{dir}}" 無效。請將目錄重新命名為 "{{suggestion}}" 或移除它。這是一個常見拼寫錯誤。', + "error.chain.configFrontmatterError": "無法解析 {{path}} 中的 frontmatter:\n{{message}}", + "error.chain.configInvalid": "設定檔 {{path}} 無效", + "error.chain.configInvalidWithMessage": "設定檔 {{path}} 無效: {{message}}", + + "notification.permission.title": "需要權限", + "notification.permission.description": "{{sessionTitle}}({{projectName}})需要權限", + "notification.question.title": "問題", + "notification.question.description": "{{sessionTitle}}({{projectName}})有一個問題", + "notification.action.goToSession": "前往工作階段", + + "notification.session.responseReady.title": "回覆已就緒", + "notification.session.error.title": "工作階段錯誤", + "notification.session.error.fallbackDescription": "發生錯誤", + + "home.recentProjects": "最近專案", + "home.empty.title": "沒有最近專案", + "home.empty.description": "透過開啟本地專案開始使用", + + "session.tab.session": "工作階段", + "session.tab.review": "審查", + "session.tab.context": "上下文", + "session.panel.reviewAndFiles": "審查與檔案", + "session.review.filesChanged": "{{count}} 個檔案變更", + "session.review.loadingChanges": "正在載入變更...", + "session.review.empty": "此工作階段暫無變更", + "session.messages.renderEarlier": "顯示更早的訊息", + "session.messages.loadingEarlier": "正在載入更早的訊息...", + "session.messages.loadEarlier": "載入更早的訊息", + "session.messages.loading": "正在載入訊息...", + + "session.context.addToContext": "將 {{selection}} 新增到上下文", + + "session.new.worktree.main": "主分支", + "session.new.worktree.mainWithBranch": "主分支 ({{branch}})", + "session.new.worktree.create": "建立新的 worktree", + "session.new.lastModified": "最後修改", + + "session.header.search.placeholder": "搜尋 {{project}}", + "session.header.searchFiles": "搜尋檔案", + + "session.share.popover.title": "發佈到網頁", + "session.share.popover.description.shared": "此工作階段已在網頁上公開。任何擁有連結的人都可以存取。", + "session.share.popover.description.unshared": "在網頁上公開分享此工作階段。任何擁有連結的人都可以存取。", + "session.share.action.share": "分享", + "session.share.action.publish": "發佈", + "session.share.action.publishing": "正在發佈...", + "session.share.action.unpublish": "取消發佈", + "session.share.action.unpublishing": "正在取消發佈...", + "session.share.action.view": "檢視", + "session.share.copy.copied": "已複製", + "session.share.copy.copyLink": "複製連結", + + "lsp.tooltip.none": "沒有 LSP 伺服器", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "正在載入提示...", + "terminal.loading": "正在載入終端機...", + "terminal.title": "終端機", + "terminal.title.numbered": "終端機 {{number}}", + "terminal.close": "關閉終端機", + + "common.closeTab": "關閉標籤頁", + "common.dismiss": "忽略", + "common.requestFailed": "要求失敗", + "common.moreOptions": "更多選項", + "common.learnMore": "深入了解", + "common.rename": "重新命名", + "common.reset": "重設", + "common.archive": "封存", + "common.delete": "刪除", + "common.close": "關閉", + "common.edit": "編輯", + "common.loadMore": "載入更多", + + "sidebar.nav.projectsAndSessions": "專案與工作階段", + "sidebar.settings": "設定", + "sidebar.help": "說明", + "sidebar.workspaces.enable": "啟用工作區", + "sidebar.workspaces.disable": "停用工作區", + "sidebar.gettingStarted.title": "開始使用", + "sidebar.gettingStarted.line1": "OpenCode 提供免費模型,你可以立即開始使用。", + "sidebar.gettingStarted.line2": "連線任意提供者即可使用更多模型,如 Claude、GPT、Gemini 等。", + "sidebar.project.recentSessions": "最近工作階段", + "sidebar.project.viewAllSessions": "查看全部工作階段", + + "settings.section.desktop": "桌面", + "settings.tab.general": "一般", + "settings.tab.shortcuts": "快速鍵", + + "settings.general.section.appearance": "外觀", + "settings.general.section.notifications": "系統通知", + "settings.general.section.sounds": "音效", + + "settings.general.row.language.title": "語言", + "settings.general.row.language.description": "變更 OpenCode 的顯示語言", + "settings.general.row.appearance.title": "外觀", + "settings.general.row.appearance.description": "自訂 OpenCode 在你的裝置上的外觀", + "settings.general.row.theme.title": "主題", + "settings.general.row.theme.description": "自訂 OpenCode 的主題。", + "settings.general.row.font.title": "字型", + "settings.general.row.font.description": "自訂程式碼區塊使用的等寬字型", + + "settings.general.notifications.agent.title": "代理程式", + "settings.general.notifications.agent.description": "當代理程式完成或需要注意時顯示系統通知", + "settings.general.notifications.permissions.title": "權限", + "settings.general.notifications.permissions.description": "當需要權限時顯示系統通知", + "settings.general.notifications.errors.title": "錯誤", + "settings.general.notifications.errors.description": "發生錯誤時顯示系統通知", + + "settings.general.sounds.agent.title": "代理程式", + "settings.general.sounds.agent.description": "當代理程式完成或需要注意時播放聲音", + "settings.general.sounds.permissions.title": "權限", + "settings.general.sounds.permissions.description": "當需要權限時播放聲音", + "settings.general.sounds.errors.title": "錯誤", + "settings.general.sounds.errors.description": "發生錯誤時播放聲音", + + "settings.shortcuts.title": "鍵盤快速鍵", + "settings.shortcuts.reset.button": "重設為預設值", + "settings.shortcuts.reset.toast.title": "快速鍵已重設", + "settings.shortcuts.reset.toast.description": "鍵盤快速鍵已重設為預設設定。", + "settings.shortcuts.conflict.title": "快速鍵已被占用", + "settings.shortcuts.conflict.description": "{{keybind}} 已分配給 {{titles}}。", + "settings.shortcuts.unassigned": "未設定", + "settings.shortcuts.pressKeys": "按下按鍵", + "settings.shortcuts.search.placeholder": "搜尋快速鍵", + "settings.shortcuts.search.empty": "找不到快速鍵", + + "settings.shortcuts.group.general": "一般", + "settings.shortcuts.group.session": "工作階段", + "settings.shortcuts.group.navigation": "導覽", + "settings.shortcuts.group.modelAndAgent": "模型與代理程式", + "settings.shortcuts.group.terminal": "終端機", + "settings.shortcuts.group.prompt": "提示", + + "settings.providers.title": "提供者", + "settings.providers.description": "提供者設定將在此處可設定。", + "settings.models.title": "模型", + "settings.models.description": "模型設定將在此處可設定。", + "settings.agents.title": "代理程式", + "settings.agents.description": "代理程式設定將在此處可設定。", + "settings.commands.title": "命令", + "settings.commands.description": "命令設定將在此處可設定。", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP 設定將在此處可設定。", + + "settings.permissions.title": "權限", + "settings.permissions.description": "控制伺服器預設可以使用哪些工具。", + "settings.permissions.section.tools": "工具", + "settings.permissions.toast.updateFailed.title": "更新權限失敗", + + "settings.permissions.action.allow": "允許", + "settings.permissions.action.ask": "詢問", + "settings.permissions.action.deny": "拒絕", + + "settings.permissions.tool.read.title": "讀取", + "settings.permissions.tool.read.description": "讀取檔案(符合檔案路徑)", + "settings.permissions.tool.edit.title": "編輯", + "settings.permissions.tool.edit.description": "修改檔案,包括編輯、寫入、修補和多重編輯", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "使用 glob 模式符合檔案", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "使用正規表示式搜尋檔案內容", + "settings.permissions.tool.list.title": "清單", + "settings.permissions.tool.list.description": "列出目錄中的檔案", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "執行 shell 命令", + "settings.permissions.tool.task.title": "Task", + "settings.permissions.tool.task.description": "啟動子代理程式", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "按名稱載入技能", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "執行語言伺服器查詢", + "settings.permissions.tool.todoread.title": "讀取待辦", + "settings.permissions.tool.todoread.description": "讀取待辦清單", + "settings.permissions.tool.todowrite.title": "更新待辦", + "settings.permissions.tool.todowrite.description": "更新待辦清單", + "settings.permissions.tool.webfetch.title": "Web Fetch", + "settings.permissions.tool.webfetch.description": "從 URL 取得內容", + "settings.permissions.tool.websearch.title": "Web Search", + "settings.permissions.tool.websearch.description": "搜尋網頁", + "settings.permissions.tool.codesearch.title": "Code Search", + "settings.permissions.tool.codesearch.description": "在網路上搜尋程式碼", + "settings.permissions.tool.external_directory.title": "外部目錄", + "settings.permissions.tool.external_directory.description": "存取專案目錄之外的檔案", + "settings.permissions.tool.doom_loop.title": "Doom Loop", + "settings.permissions.tool.doom_loop.description": "偵測具有相同輸入的重複工具呼叫", + + "session.delete.failed.title": "刪除工作階段失敗", + "session.delete.title": "刪除工作階段", + "session.delete.confirm": '刪除工作階段 "{{name}}"?', + "session.delete.button": "刪除工作階段", + + "workspace.new": "新增工作區", + "workspace.type.local": "本地", + "workspace.type.sandbox": "沙盒", + "workspace.create.failed.title": "建立工作區失敗", + "workspace.delete.failed.title": "刪除工作區失敗", + "workspace.resetting.title": "正在重設工作區", + "workspace.resetting.description": "這可能需要一點時間。", + "workspace.reset.failed.title": "重設工作區失敗", + "workspace.reset.success.title": "工作區已重設", + "workspace.reset.success.description": "工作區已與預設分支保持一致。", + "workspace.status.checking": "正在檢查未合併的變更...", + "workspace.status.error": "無法驗證 git 狀態。", + "workspace.status.clean": "未偵測到未合併的變更。", + "workspace.status.dirty": "偵測到未合併的變更。", + "workspace.delete.title": "刪除工作區", + "workspace.delete.confirm": '刪除工作區 "{{name}}"?', + "workspace.delete.button": "刪除工作區", + "workspace.reset.title": "重設工作區", + "workspace.reset.confirm": '重設工作區 "{{name}}"?', + "workspace.reset.button": "重設工作區", + "workspace.reset.archived.none": "不會封存任何作用中工作階段。", + "workspace.reset.archived.one": "將封存 1 個工作階段。", + "workspace.reset.archived.many": "將封存 {{count}} 個工作階段。", + "workspace.reset.note": "這將把工作區重設為與預設分支一致。", +} satisfies Partial> diff --git a/packages/app/src/index.css b/packages/app/src/index.css new file mode 100644 index 00000000000..3d7b9db7af9 --- /dev/null +++ b/packages/app/src/index.css @@ -0,0 +1,57 @@ +@import "@opencode-ai/ui/styles/tailwind"; + +:root { + a { + cursor: default; + } +} + +[data-component="markdown"] ul { + list-style: disc outside; + padding-left: 1.5rem; +} + +[data-component="markdown"] ol { + list-style: decimal outside; + padding-left: 1.5rem; +} + +[data-component="markdown"] li > p:first-child { + display: inline; + margin: 0; +} + +[data-component="markdown"] li > p + p { + display: block; + margin-top: 0.5rem; +} + +*[data-tauri-drag-region] { + app-region: drag; +} + +.session-scroller::-webkit-scrollbar { + width: 10px !important; + height: 10px !important; +} + +.session-scroller::-webkit-scrollbar-track { + background: transparent !important; + border-radius: 5px !important; +} + +.session-scroller::-webkit-scrollbar-thumb { + background: var(--border-weak-base) !important; + border-radius: 5px !important; + border: 3px solid transparent !important; + background-clip: padding-box !important; +} + +.session-scroller::-webkit-scrollbar-thumb:hover { + background: var(--border-weak-base) !important; +} + +.session-scroller { + scrollbar-width: thin !important; + scrollbar-color: var(--border-weak-base) transparent !important; +} diff --git a/packages/app/src/index.ts b/packages/app/src/index.ts new file mode 100644 index 00000000000..df3181133e9 --- /dev/null +++ b/packages/app/src/index.ts @@ -0,0 +1,2 @@ +export { PlatformProvider, type Platform } from "./context/platform" +export { AppBaseProviders, AppInterface } from "./app" diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx new file mode 100644 index 00000000000..dca02489a8a --- /dev/null +++ b/packages/app/src/pages/directory-layout.tsx @@ -0,0 +1,57 @@ +import { createMemo, Show, type ParentProps } from "solid-js" +import { useNavigate, useParams } from "@solidjs/router" +import { SDKProvider, useSDK } from "@/context/sdk" +import { SyncProvider, useSync } from "@/context/sync" +import { LocalProvider } from "@/context/local" + +import { base64Decode } from "@opencode-ai/util/encode" +import { DataProvider } from "@opencode-ai/ui/context" +import { iife } from "@opencode-ai/util/iife" +import type { QuestionAnswer } from "@opencode-ai/sdk/v2" + +export default function Layout(props: ParentProps) { + const params = useParams() + const navigate = useNavigate() + const directory = createMemo(() => { + return base64Decode(params.dir!) + }) + return ( + + + + {iife(() => { + const sync = useSync() + const sdk = useSDK() + const respond = (input: { + sessionID: string + permissionID: string + response: "once" | "always" | "reject" + }) => sdk.client.permission.respond(input) + + const replyToQuestion = (input: { requestID: string; answers: QuestionAnswer[] }) => + sdk.client.question.reply(input) + + const rejectQuestion = (input: { requestID: string }) => sdk.client.question.reject(input) + + const navigateToSession = (sessionID: string) => { + navigate(`/${params.dir}/session/${sessionID}`) + } + + return ( + + {props.children} + + ) + })} + + + + ) +} diff --git a/packages/app/src/pages/error.tsx b/packages/app/src/pages/error.tsx new file mode 100644 index 00000000000..6d6faf6fa3b --- /dev/null +++ b/packages/app/src/pages/error.tsx @@ -0,0 +1,290 @@ +import { TextField } from "@opencode-ai/ui/text-field" +import { Logo } from "@opencode-ai/ui/logo" +import { Button } from "@opencode-ai/ui/button" +import { Component, Show } from "solid-js" +import { createStore } from "solid-js/store" +import { usePlatform } from "@/context/platform" +import { useLanguage } from "@/context/language" +import { Icon } from "@opencode-ai/ui/icon" + +export type InitError = { + name: string + data: Record +} + +type Translator = ReturnType["t"] + +function isInitError(error: unknown): error is InitError { + return ( + typeof error === "object" && + error !== null && + "name" in error && + "data" in error && + typeof (error as InitError).data === "object" + ) +} + +function safeJson(value: unknown): string { + const seen = new WeakSet() + const json = JSON.stringify( + value, + (_key, val) => { + if (typeof val === "bigint") return val.toString() + if (typeof val === "object" && val) { + if (seen.has(val)) return "[Circular]" + seen.add(val) + } + return val + }, + 2, + ) + return json ?? String(value) +} + +function formatInitError(error: InitError, t: Translator): string { + const data = error.data + switch (error.name) { + case "MCPFailed": { + const name = typeof data.name === "string" ? data.name : "" + return t("error.chain.mcpFailed", { name }) + } + case "ProviderAuthError": { + const providerID = typeof data.providerID === "string" ? data.providerID : "unknown" + const message = typeof data.message === "string" ? data.message : safeJson(data.message) + return t("error.chain.providerAuthFailed", { provider: providerID, message }) + } + case "APIError": { + const message = typeof data.message === "string" ? data.message : t("error.chain.apiError") + const lines: string[] = [message] + + if (typeof data.statusCode === "number") { + lines.push(t("error.chain.status", { status: data.statusCode })) + } + + if (typeof data.isRetryable === "boolean") { + lines.push(t("error.chain.retryable", { retryable: data.isRetryable })) + } + + if (typeof data.responseBody === "string" && data.responseBody) { + lines.push(t("error.chain.responseBody", { body: data.responseBody })) + } + + return lines.join("\n") + } + case "ProviderModelNotFoundError": { + const { providerID, modelID, suggestions } = data as { + providerID: string + modelID: string + suggestions?: string[] + } + + const suggestionsLine = + Array.isArray(suggestions) && suggestions.length + ? [t("error.chain.didYouMean", { suggestions: suggestions.join(", ") })] + : [] + + return [ + t("error.chain.modelNotFound", { provider: providerID, model: modelID }), + ...suggestionsLine, + t("error.chain.checkConfig"), + ].join("\n") + } + case "ProviderInitError": { + const providerID = typeof data.providerID === "string" ? data.providerID : "unknown" + return t("error.chain.providerInitFailed", { provider: providerID }) + } + case "ConfigJsonError": { + const path = typeof data.path === "string" ? data.path : safeJson(data.path) + const message = typeof data.message === "string" ? data.message : "" + if (message) return t("error.chain.configJsonInvalidWithMessage", { path, message }) + return t("error.chain.configJsonInvalid", { path }) + } + case "ConfigDirectoryTypoError": { + const path = typeof data.path === "string" ? data.path : safeJson(data.path) + const dir = typeof data.dir === "string" ? data.dir : safeJson(data.dir) + const suggestion = typeof data.suggestion === "string" ? data.suggestion : safeJson(data.suggestion) + return t("error.chain.configDirectoryTypo", { dir, path, suggestion }) + } + case "ConfigFrontmatterError": { + const path = typeof data.path === "string" ? data.path : safeJson(data.path) + const message = typeof data.message === "string" ? data.message : safeJson(data.message) + return t("error.chain.configFrontmatterError", { path, message }) + } + case "ConfigInvalidError": { + const issues = Array.isArray(data.issues) + ? data.issues.map( + (issue: { message: string; path: string[] }) => "↳ " + issue.message + " " + issue.path.join("."), + ) + : [] + const message = typeof data.message === "string" ? data.message : "" + const path = typeof data.path === "string" ? data.path : safeJson(data.path) + + const line = message + ? t("error.chain.configInvalidWithMessage", { path, message }) + : t("error.chain.configInvalid", { path }) + + return [line, ...issues].join("\n") + } + case "UnknownError": + return typeof data.message === "string" ? data.message : safeJson(data) + default: + if (typeof data.message === "string") return data.message + return safeJson(data) + } +} + +function formatErrorChain(error: unknown, t: Translator, depth = 0, parentMessage?: string): string { + if (!error) return t("error.chain.unknown") + + if (isInitError(error)) { + const message = formatInitError(error, t) + if (depth > 0 && parentMessage === message) return "" + const indent = depth > 0 ? `\n${"─".repeat(40)}\n${t("error.chain.causedBy")}\n` : "" + return indent + `${error.name}\n${message}` + } + + if (error instanceof Error) { + const isDuplicate = depth > 0 && parentMessage === error.message + const parts: string[] = [] + const indent = depth > 0 ? `\n${"─".repeat(40)}\n${t("error.chain.causedBy")}\n` : "" + + const header = `${error.name}${error.message ? `: ${error.message}` : ""}` + const stack = error.stack?.trim() + + if (stack) { + const startsWithHeader = stack.startsWith(header) + + if (isDuplicate && startsWithHeader) { + const trace = stack.split("\n").slice(1).join("\n").trim() + if (trace) { + parts.push(indent + trace) + } + } + + if (isDuplicate && !startsWithHeader) { + parts.push(indent + stack) + } + + if (!isDuplicate && startsWithHeader) { + parts.push(indent + stack) + } + + if (!isDuplicate && !startsWithHeader) { + parts.push(indent + `${header}\n${stack}`) + } + } + + if (!stack && !isDuplicate) { + parts.push(indent + header) + } + + if (error.cause) { + const causeResult = formatErrorChain(error.cause, t, depth + 1, error.message) + if (causeResult) { + parts.push(causeResult) + } + } + + return parts.join("\n\n") + } + + if (typeof error === "string") { + if (depth > 0 && parentMessage === error) return "" + const indent = depth > 0 ? `\n${"─".repeat(40)}\n${t("error.chain.causedBy")}\n` : "" + return indent + error + } + + const indent = depth > 0 ? `\n${"─".repeat(40)}\n${t("error.chain.causedBy")}\n` : "" + return indent + safeJson(error) +} + +function formatError(error: unknown, t: Translator): string { + return formatErrorChain(error, t, 0) +} + +interface ErrorPageProps { + error: unknown +} + +export const ErrorPage: Component = (props) => { + const platform = usePlatform() + const language = useLanguage() + const [store, setStore] = createStore({ + checking: false, + version: undefined as string | undefined, + }) + + async function checkForUpdates() { + if (!platform.checkUpdate) return + setStore("checking", true) + const result = await platform.checkUpdate() + setStore("checking", false) + if (result.updateAvailable && result.version) setStore("version", result.version) + } + + async function installUpdate() { + if (!platform.update || !platform.restart) return + await platform.update() + await platform.restart() + } + + return ( +
+
+ +
+

{language.t("error.page.title")}

+

{language.t("error.page.description")}

+
+ +
+ + + + {store.checking + ? language.t("error.page.action.checking") + : language.t("error.page.action.checkUpdates")} + + } + > + + + +
+
+
+ {language.t("error.page.report.prefix")} + +
+ + {(version) => ( +

{language.t("error.page.version", { version: version() })}

+ )} +
+
+
+
+ ) +} diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx new file mode 100644 index 00000000000..4007129b5cc --- /dev/null +++ b/packages/app/src/pages/home.tsx @@ -0,0 +1,125 @@ +import { createMemo, For, Match, Show, Switch } from "solid-js" +import { Button } from "@opencode-ai/ui/button" +import { Logo } from "@opencode-ai/ui/logo" +import { useLayout } from "@/context/layout" +import { useNavigate } from "@solidjs/router" +import { base64Encode } from "@opencode-ai/util/encode" +import { Icon } from "@opencode-ai/ui/icon" +import { usePlatform } from "@/context/platform" +import { DateTime } from "luxon" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { DialogSelectDirectory } from "@/components/dialog-select-directory" +import { DialogSelectServer } from "@/components/dialog-select-server" +import { useServer } from "@/context/server" +import { useGlobalSync } from "@/context/global-sync" +import { useLanguage } from "@/context/language" + +export default function Home() { + const sync = useGlobalSync() + const layout = useLayout() + const platform = usePlatform() + const dialog = useDialog() + const navigate = useNavigate() + const server = useServer() + const language = useLanguage() + const homedir = createMemo(() => sync.data.path.home) + + function openProject(directory: string) { + layout.projects.open(directory) + server.projects.touch(directory) + navigate(`/${base64Encode(directory)}`) + } + + async function chooseProject() { + function resolve(result: string | string[] | null) { + if (Array.isArray(result)) { + for (const directory of result) { + openProject(directory) + } + } else if (result) { + openProject(result) + } + } + + if (platform.openDirectoryPickerDialog && server.isLocal()) { + const result = await platform.openDirectoryPickerDialog?.({ + title: language.t("command.project.open"), + multiple: true, + }) + resolve(result) + } else { + dialog.show( + () => , + () => resolve(null), + ) + } + } + + return ( +
+ + + + 0}> +
+
+
{language.t("home.recentProjects")}
+ +
+
    + (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)) + .slice(0, 5)} + > + {(project) => ( + + )} + +
+
+
+ +
+ +
+
{language.t("home.empty.title")}
+
{language.t("home.empty.description")}
+
+
+ +
+ + +
+ ) +} diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx new file mode 100644 index 00000000000..c4fd07e57ce --- /dev/null +++ b/packages/app/src/pages/layout.tsx @@ -0,0 +1,2555 @@ +import { + batch, + createEffect, + createMemo, + createSignal, + For, + Match, + on, + onCleanup, + onMount, + ParentProps, + Show, + Switch, + untrack, + type Accessor, + type JSX, +} from "solid-js" +import { A, useNavigate, useParams } from "@solidjs/router" +import { useLayout, getAvatarColors, LocalProject } from "@/context/layout" +import { useGlobalSync } from "@/context/global-sync" +import { Persist, persisted } from "@/utils/persist" +import { base64Decode, base64Encode } from "@opencode-ai/util/encode" +import { Avatar } from "@opencode-ai/ui/avatar" +import { ResizeHandle } from "@opencode-ai/ui/resize-handle" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { InlineInput } from "@opencode-ai/ui/inline-input" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { HoverCard } from "@opencode-ai/ui/hover-card" +import { MessageNav } from "@opencode-ai/ui/message-nav" +import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" +import { Collapsible } from "@opencode-ai/ui/collapsible" +import { DiffChanges } from "@opencode-ai/ui/diff-changes" +import { Spinner } from "@opencode-ai/ui/spinner" +import { Dialog } from "@opencode-ai/ui/dialog" +import { getFilename } from "@opencode-ai/util/path" +import { Session, type Message, type TextPart } from "@opencode-ai/sdk/v2/client" +import { usePlatform } from "@/context/platform" +import { useSettings } from "@/context/settings" +import { createStore, produce, reconcile } from "solid-js/store" +import { + DragDropProvider, + DragDropSensors, + DragOverlay, + SortableProvider, + closestCenter, + createSortable, +} from "@thisbeyond/solid-dnd" +import type { DragEvent } from "@thisbeyond/solid-dnd" +import { useProviders } from "@/hooks/use-providers" +import { showToast, Toast, toaster } from "@opencode-ai/ui/toast" +import { useGlobalSDK } from "@/context/global-sdk" +import { useNotification } from "@/context/notification" +import { usePermission } from "@/context/permission" +import { Binary } from "@opencode-ai/util/binary" +import { retry } from "@opencode-ai/util/retry" +import { playSound, soundSrc } from "@/utils/sound" + +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme" +import { DialogSelectProvider } from "@/components/dialog-select-provider" +import { DialogSelectServer } from "@/components/dialog-select-server" +import { DialogSettings } from "@/components/dialog-settings" +import { useCommand, type CommandOption } from "@/context/command" +import { ConstrainDragXAxis } from "@/utils/solid-dnd" +import { navStart } from "@/utils/perf" +import { DialogSelectDirectory } from "@/components/dialog-select-directory" +import { DialogEditProject } from "@/components/dialog-edit-project" +import { Titlebar } from "@/components/titlebar" +import { useServer } from "@/context/server" +import { useLanguage, type Locale } from "@/context/language" + +export default function Layout(props: ParentProps) { + const [store, setStore, , ready] = persisted( + Persist.global("layout.page", ["layout.page.v1"]), + createStore({ + lastSession: {} as { [directory: string]: string }, + activeProject: undefined as string | undefined, + activeWorkspace: undefined as string | undefined, + workspaceOrder: {} as Record, + workspaceName: {} as Record, + workspaceBranchName: {} as Record>, + workspaceExpanded: {} as Record, + }), + ) + + const pageReady = createMemo(() => ready()) + + let scrollContainerRef: HTMLDivElement | undefined + const xlQuery = window.matchMedia("(min-width: 1280px)") + const [isLargeViewport, setIsLargeViewport] = createSignal(xlQuery.matches) + const handleViewportChange = (e: MediaQueryListEvent) => setIsLargeViewport(e.matches) + xlQuery.addEventListener("change", handleViewportChange) + onCleanup(() => xlQuery.removeEventListener("change", handleViewportChange)) + + const params = useParams() + const [autoselect, setAutoselect] = createSignal(!params.dir) + const globalSDK = useGlobalSDK() + const globalSync = useGlobalSync() + const layout = useLayout() + const layoutReady = createMemo(() => layout.ready()) + const platform = usePlatform() + const settings = useSettings() + const server = useServer() + const notification = useNotification() + const permission = usePermission() + const navigate = useNavigate() + const providers = useProviders() + const dialog = useDialog() + const command = useCommand() + const theme = useTheme() + const language = useLanguage() + const initialDir = params.dir + const availableThemeEntries = createMemo(() => Object.entries(theme.themes())) + const colorSchemeOrder: ColorScheme[] = ["system", "light", "dark"] + const colorSchemeKey: Record = { + system: "theme.scheme.system", + light: "theme.scheme.light", + dark: "theme.scheme.dark", + } + const colorSchemeLabel = (scheme: ColorScheme) => language.t(colorSchemeKey[scheme]) + + const [editor, setEditor] = createStore({ + active: "" as string, + value: "", + }) + const [busyWorkspaces, setBusyWorkspaces] = createSignal>(new Set()) + const setBusy = (directory: string, value: boolean) => { + const key = workspaceKey(directory) + setBusyWorkspaces((prev) => { + const next = new Set(prev) + if (value) next.add(key) + else next.delete(key) + return next + }) + } + const isBusy = (directory: string) => busyWorkspaces().has(workspaceKey(directory)) + const editorRef = { current: undefined as HTMLInputElement | undefined } + + const [hoverSession, setHoverSession] = createSignal() + + const autoselecting = createMemo(() => { + if (params.dir) return false + if (initialDir) return false + if (!autoselect()) return false + if (!pageReady()) return true + if (!layoutReady()) return true + const list = layout.projects.list() + if (list.length === 0) return false + return true + }) + + const editorOpen = (id: string) => editor.active === id + const editorValue = () => editor.value + + const openEditor = (id: string, value: string) => { + if (!id) return + setEditor({ active: id, value }) + } + + const closeEditor = () => setEditor({ active: "", value: "" }) + + const saveEditor = (callback: (next: string) => void) => { + const next = editor.value.trim() + if (!next) { + closeEditor() + return + } + closeEditor() + callback(next) + } + + const editorKeyDown = (event: KeyboardEvent, callback: (next: string) => void) => { + if (event.key === "Enter") { + event.preventDefault() + saveEditor(callback) + return + } + if (event.key === "Escape") { + event.preventDefault() + closeEditor() + } + } + + const InlineEditor = (props: { + id: string + value: Accessor + onSave: (next: string) => void + class?: string + displayClass?: string + editing?: boolean + stopPropagation?: boolean + openOnDblClick?: boolean + }) => { + const isEditing = () => props.editing ?? editorOpen(props.id) + const stopEvents = () => props.stopPropagation ?? false + const allowDblClick = () => props.openOnDblClick ?? true + const stopPropagation = (event: Event) => { + if (!stopEvents()) return + event.stopPropagation() + } + const handleDblClick = (event: MouseEvent) => { + if (!allowDblClick()) return + stopPropagation(event) + openEditor(props.id, props.value()) + } + + return ( + + {props.value()} + + } + > + { + editorRef.current = el + requestAnimationFrame(() => el.focus()) + }} + value={editorValue()} + class={props.class} + onInput={(event) => setEditor("value", event.currentTarget.value)} + onKeyDown={(event) => { + event.stopPropagation() + editorKeyDown(event, props.onSave) + }} + onBlur={() => closeEditor()} + onPointerDown={stopPropagation} + onClick={stopPropagation} + onDblClick={stopPropagation} + onMouseDown={stopPropagation} + onMouseUp={stopPropagation} + onTouchStart={stopPropagation} + /> + + ) + } + + function cycleTheme(direction = 1) { + const ids = availableThemeEntries().map(([id]) => id) + if (ids.length === 0) return + const currentIndex = ids.indexOf(theme.themeId()) + const nextIndex = currentIndex === -1 ? 0 : (currentIndex + direction + ids.length) % ids.length + const nextThemeId = ids[nextIndex] + theme.setTheme(nextThemeId) + const nextTheme = theme.themes()[nextThemeId] + showToast({ + title: language.t("toast.theme.title"), + description: nextTheme?.name ?? nextThemeId, + }) + } + + function cycleColorScheme(direction = 1) { + const current = theme.colorScheme() + const currentIndex = colorSchemeOrder.indexOf(current) + const nextIndex = + currentIndex === -1 ? 0 : (currentIndex + direction + colorSchemeOrder.length) % colorSchemeOrder.length + const next = colorSchemeOrder[nextIndex] + theme.setColorScheme(next) + showToast({ + title: language.t("toast.scheme.title"), + description: colorSchemeLabel(next), + }) + } + + function setLocale(next: Locale) { + if (next === language.locale()) return + language.setLocale(next) + showToast({ + title: language.t("toast.language.title"), + description: language.t("toast.language.description", { language: language.label(next) }), + }) + } + + function cycleLanguage(direction = 1) { + const locales = language.locales + const currentIndex = locales.indexOf(language.locale()) + const nextIndex = currentIndex === -1 ? 0 : (currentIndex + direction + locales.length) % locales.length + const next = locales[nextIndex] + if (!next) return + setLocale(next) + } + + onMount(() => { + if (!platform.checkUpdate || !platform.update || !platform.restart) return + + let toastId: number | undefined + + async function pollUpdate() { + const { updateAvailable, version } = await platform.checkUpdate!() + if (updateAvailable && toastId === undefined) { + toastId = showToast({ + persistent: true, + icon: "download", + title: language.t("toast.update.title"), + description: language.t("toast.update.description", { version: version ?? "" }), + actions: [ + { + label: language.t("toast.update.action.installRestart"), + onClick: async () => { + await platform.update!() + await platform.restart!() + }, + }, + { + label: language.t("toast.update.action.notYet"), + onClick: "dismiss", + }, + ], + }) + } + } + + pollUpdate() + const interval = setInterval(pollUpdate, 10 * 60 * 1000) + onCleanup(() => clearInterval(interval)) + }) + + onMount(() => { + const toastBySession = new Map() + const alertedAtBySession = new Map() + const cooldownMs = 5000 + + const unsub = globalSDK.event.listen((e) => { + if (e.details?.type !== "permission.asked" && e.details?.type !== "question.asked") return + const title = + e.details.type === "permission.asked" + ? language.t("notification.permission.title") + : language.t("notification.question.title") + const icon = e.details.type === "permission.asked" ? ("checklist" as const) : ("bubble-5" as const) + const directory = e.name + const props = e.details.properties + if (e.details.type === "permission.asked" && permission.autoResponds(e.details.properties, directory)) return + + const [store] = globalSync.child(directory) + const session = store.session.find((s) => s.id === props.sessionID) + const sessionKey = `${directory}:${props.sessionID}` + + const sessionTitle = session?.title ?? language.t("command.session.new") + const projectName = getFilename(directory) + const description = + e.details.type === "permission.asked" + ? language.t("notification.permission.description", { sessionTitle, projectName }) + : language.t("notification.question.description", { sessionTitle, projectName }) + const href = `/${base64Encode(directory)}/session/${props.sessionID}` + + const now = Date.now() + const lastAlerted = alertedAtBySession.get(sessionKey) ?? 0 + if (now - lastAlerted < cooldownMs) return + alertedAtBySession.set(sessionKey, now) + + if (e.details.type === "permission.asked") { + playSound(soundSrc(settings.sounds.permissions())) + if (settings.notifications.permissions()) { + void platform.notify(title, description, href) + } + } + + if (e.details.type === "question.asked") { + if (settings.notifications.agent()) { + void platform.notify(title, description, href) + } + } + + const currentDir = params.dir ? base64Decode(params.dir) : undefined + const currentSession = params.id + if (directory === currentDir && props.sessionID === currentSession) return + if (directory === currentDir && session?.parentID === currentSession) return + + const existingToastId = toastBySession.get(sessionKey) + if (existingToastId !== undefined) toaster.dismiss(existingToastId) + + const toastId = showToast({ + persistent: true, + icon, + title, + description, + actions: [ + { + label: language.t("notification.action.goToSession"), + onClick: () => navigate(href), + }, + { + label: language.t("common.dismiss"), + onClick: "dismiss", + }, + ], + }) + toastBySession.set(sessionKey, toastId) + }) + onCleanup(unsub) + + createEffect(() => { + const currentDir = params.dir ? base64Decode(params.dir) : undefined + const currentSession = params.id + if (!currentDir || !currentSession) return + const sessionKey = `${currentDir}:${currentSession}` + const toastId = toastBySession.get(sessionKey) + if (toastId !== undefined) { + toaster.dismiss(toastId) + toastBySession.delete(sessionKey) + alertedAtBySession.delete(sessionKey) + } + const [store] = globalSync.child(currentDir) + const childSessions = store.session.filter((s) => s.parentID === currentSession) + for (const child of childSessions) { + const childKey = `${currentDir}:${child.id}` + const childToastId = toastBySession.get(childKey) + if (childToastId !== undefined) { + toaster.dismiss(childToastId) + toastBySession.delete(childKey) + alertedAtBySession.delete(childKey) + } + } + }) + }) + + function sortSessions(a: Session, b: Session) { + const now = Date.now() + const oneMinuteAgo = now - 60 * 1000 + const aUpdated = a.time.updated ?? a.time.created + const bUpdated = b.time.updated ?? b.time.created + const aRecent = aUpdated > oneMinuteAgo + const bRecent = bUpdated > oneMinuteAgo + if (aRecent && bRecent) return a.id.localeCompare(b.id) + if (aRecent && !bRecent) return -1 + if (!aRecent && bRecent) return 1 + return bUpdated - aUpdated + } + + const [scrollSessionKey, setScrollSessionKey] = createSignal(undefined) + + function scrollToSession(sessionId: string, sessionKey: string) { + if (!scrollContainerRef) return + if (scrollSessionKey() === sessionKey) return + const element = scrollContainerRef.querySelector(`[data-session-id="${sessionId}"]`) + if (!element) return + const containerRect = scrollContainerRef.getBoundingClientRect() + const elementRect = element.getBoundingClientRect() + if (elementRect.top >= containerRect.top && elementRect.bottom <= containerRect.bottom) { + setScrollSessionKey(sessionKey) + return + } + setScrollSessionKey(sessionKey) + element.scrollIntoView({ block: "nearest", behavior: "smooth" }) + } + + const currentProject = createMemo(() => { + const directory = params.dir ? base64Decode(params.dir) : undefined + if (!directory) return + + const projects = layout.projects.list() + + const sandbox = projects.find((p) => p.sandboxes?.includes(directory)) + if (sandbox) return sandbox + + const direct = projects.find((p) => p.worktree === directory) + if (direct) return direct + + const [child] = globalSync.child(directory) + const id = child.project + if (!id) return + + const meta = globalSync.data.project.find((p) => p.id === id) + const root = meta?.worktree + if (!root) return + + return projects.find((p) => p.worktree === root) + }) + + createEffect( + on( + () => ({ ready: pageReady(), project: currentProject() }), + (value) => { + if (!value.ready) return + const project = value.project + if (!project) return + const last = server.projects.last() + if (last === project.worktree) return + server.projects.touch(project.worktree) + }, + { defer: true }, + ), + ) + + createEffect( + on( + () => ({ ready: pageReady(), layoutReady: layoutReady(), dir: params.dir, list: layout.projects.list() }), + (value) => { + if (!value.ready) return + if (!value.layoutReady) return + if (!autoselect()) return + if (initialDir) return + if (value.dir) return + if (value.list.length === 0) return + + const last = server.projects.last() + const next = value.list.find((project) => project.worktree === last) ?? value.list[0] + if (!next) return + setAutoselect(false) + openProject(next.worktree, false) + navigateToProject(next.worktree) + }, + { defer: true }, + ), + ) + + const workspaceKey = (directory: string) => directory.replace(/[\\/]+$/, "") + + const workspaceName = (directory: string, projectId?: string, branch?: string) => { + const key = workspaceKey(directory) + const direct = store.workspaceName[key] ?? store.workspaceName[directory] + if (direct) return direct + if (!projectId) return + if (!branch) return + return store.workspaceBranchName[projectId]?.[branch] + } + + const setWorkspaceName = (directory: string, next: string, projectId?: string, branch?: string) => { + const key = workspaceKey(directory) + setStore("workspaceName", (prev) => ({ ...(prev ?? {}), [key]: next })) + if (!projectId) return + if (!branch) return + setStore("workspaceBranchName", projectId, (prev) => ({ ...(prev ?? {}), [branch]: next })) + } + + const workspaceLabel = (directory: string, branch?: string, projectId?: string) => + workspaceName(directory, projectId, branch) ?? branch ?? getFilename(directory) + + const isWorkspaceEditing = () => editor.active.startsWith("workspace:") + + const workspaceSetting = createMemo(() => { + const project = currentProject() + if (!project) return false + return layout.sidebar.workspaces(project.worktree)() + }) + + createEffect(() => { + if (!pageReady()) return + if (!layoutReady()) return + const project = currentProject() + if (!project) return + + const dirs = [project.worktree, ...(project.sandboxes ?? [])] + const existing = store.workspaceOrder[project.worktree] + if (!existing) { + setStore("workspaceOrder", project.worktree, dirs) + return + } + + const keep = existing.filter((d) => dirs.includes(d)) + const missing = dirs.filter((d) => !existing.includes(d)) + const merged = [...keep, ...missing] + + if (merged.length !== existing.length) { + setStore("workspaceOrder", project.worktree, merged) + return + } + + if (merged.some((d, i) => d !== existing[i])) { + setStore("workspaceOrder", project.worktree, merged) + } + }) + + createEffect(() => { + if (!pageReady()) return + if (!layoutReady()) return + const projects = layout.projects.list() + for (const [directory, expanded] of Object.entries(store.workspaceExpanded)) { + if (!expanded) continue + const project = projects.find((item) => item.worktree === directory || item.sandboxes?.includes(directory)) + if (!project) continue + if (layout.sidebar.workspaces(project.worktree)()) continue + setStore("workspaceExpanded", directory, false) + } + }) + + const currentSessions = createMemo(() => { + const project = currentProject() + if (!project) return [] as Session[] + if (workspaceSetting()) { + const dirs = workspaceIds(project) + const activeDir = params.dir ? base64Decode(params.dir) : "" + const result: Session[] = [] + for (const dir of dirs) { + const expanded = store.workspaceExpanded[dir] ?? dir === project.worktree + const active = dir === activeDir + if (!expanded && !active) continue + const [dirStore] = globalSync.child(dir, { bootstrap: true }) + const dirSessions = dirStore.session + .filter((session) => session.directory === dirStore.path.directory) + .filter((session) => !session.parentID && !session.time?.archived) + .toSorted(sortSessions) + result.push(...dirSessions) + } + return result + } + const [projectStore] = globalSync.child(project.worktree) + return projectStore.session + .filter((session) => session.directory === projectStore.path.directory) + .filter((session) => !session.parentID && !session.time?.archived) + .toSorted(sortSessions) + }) + + type PrefetchQueue = { + inflight: Set + pending: string[] + pendingSet: Set + running: number + } + + const prefetchChunk = 600 + const prefetchConcurrency = 1 + const prefetchPendingLimit = 6 + const prefetchToken = { value: 0 } + const prefetchQueues = new Map() + + createEffect(() => { + params.dir + globalSDK.url + + prefetchToken.value += 1 + for (const q of prefetchQueues.values()) { + q.pending.length = 0 + q.pendingSet.clear() + } + }) + + const queueFor = (directory: string) => { + const existing = prefetchQueues.get(directory) + if (existing) return existing + + const created: PrefetchQueue = { + inflight: new Set(), + pending: [], + pendingSet: new Set(), + running: 0, + } + prefetchQueues.set(directory, created) + return created + } + + async function prefetchMessages(directory: string, sessionID: string, token: number) { + const [, setStore] = globalSync.child(directory) + + return retry(() => globalSDK.client.session.messages({ directory, sessionID, limit: prefetchChunk })) + .then((messages) => { + if (prefetchToken.value !== token) return + + const items = (messages.data ?? []).filter((x) => !!x?.info?.id) + const next = items + .map((x) => x.info) + .filter((m) => !!m?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + + batch(() => { + setStore("message", sessionID, reconcile(next, { key: "id" })) + + for (const message of items) { + setStore( + "part", + message.info.id, + reconcile( + message.parts + .filter((p) => !!p?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)), + { key: "id" }, + ), + ) + } + }) + }) + .catch(() => undefined) + } + + const pumpPrefetch = (directory: string) => { + const q = queueFor(directory) + if (q.running >= prefetchConcurrency) return + + const sessionID = q.pending.shift() + if (!sessionID) return + + q.pendingSet.delete(sessionID) + q.inflight.add(sessionID) + q.running += 1 + + const token = prefetchToken.value + + void prefetchMessages(directory, sessionID, token).finally(() => { + q.running -= 1 + q.inflight.delete(sessionID) + pumpPrefetch(directory) + }) + } + + const prefetchSession = (session: Session, priority: "high" | "low" = "low") => { + const directory = session.directory + if (!directory) return + + const [store] = globalSync.child(directory) + if (store.message[session.id] !== undefined) return + + const q = queueFor(directory) + if (q.inflight.has(session.id)) return + if (q.pendingSet.has(session.id)) return + + if (priority === "high") q.pending.unshift(session.id) + if (priority !== "high") q.pending.push(session.id) + q.pendingSet.add(session.id) + + while (q.pending.length > prefetchPendingLimit) { + const dropped = q.pending.pop() + if (!dropped) continue + q.pendingSet.delete(dropped) + } + + pumpPrefetch(directory) + } + + createEffect(() => { + const sessions = currentSessions() + const id = params.id + + if (!id) { + const first = sessions[0] + if (first) prefetchSession(first) + + const second = sessions[1] + if (second) prefetchSession(second) + return + } + + const index = sessions.findIndex((s) => s.id === id) + if (index === -1) return + + const next = sessions[index + 1] + if (next) prefetchSession(next) + + const prev = sessions[index - 1] + if (prev) prefetchSession(prev) + }) + + function navigateSessionByOffset(offset: number) { + const sessions = currentSessions() + if (sessions.length === 0) return + + const sessionIndex = params.id ? sessions.findIndex((s) => s.id === params.id) : -1 + + let targetIndex: number + if (sessionIndex === -1) { + targetIndex = offset > 0 ? 0 : sessions.length - 1 + } else { + targetIndex = (sessionIndex + offset + sessions.length) % sessions.length + } + + const session = sessions[targetIndex] + if (!session) return + + const next = sessions[(targetIndex + 1) % sessions.length] + const prev = sessions[(targetIndex - 1 + sessions.length) % sessions.length] + + if (offset > 0) { + if (next) prefetchSession(next, "high") + if (prev) prefetchSession(prev) + } + + if (offset < 0) { + if (prev) prefetchSession(prev, "high") + if (next) prefetchSession(next) + } + + if (import.meta.env.DEV) { + navStart({ + dir: base64Encode(session.directory), + from: params.id, + to: session.id, + trigger: offset > 0 ? "alt+arrowdown" : "alt+arrowup", + }) + } + navigateToSession(session) + queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`)) + } + + async function archiveSession(session: Session) { + const [store, setStore] = globalSync.child(session.directory) + const sessions = store.session ?? [] + const index = sessions.findIndex((s) => s.id === session.id) + const nextSession = sessions[index + 1] ?? sessions[index - 1] + + await globalSDK.client.session.update({ + directory: session.directory, + sessionID: session.id, + time: { archived: Date.now() }, + }) + setStore( + produce((draft) => { + const match = Binary.search(draft.session, session.id, (s) => s.id) + if (match.found) draft.session.splice(match.index, 1) + }), + ) + if (session.id === params.id) { + if (nextSession) { + navigate(`/${params.dir}/session/${nextSession.id}`) + } else { + navigate(`/${params.dir}/session`) + } + } + } + + async function deleteSession(session: Session) { + const [store, setStore] = globalSync.child(session.directory) + const sessions = (store.session ?? []).filter((s) => !s.parentID && !s.time?.archived) + const index = sessions.findIndex((s) => s.id === session.id) + const nextSession = sessions[index + 1] ?? sessions[index - 1] + + const result = await globalSDK.client.session + .delete({ directory: session.directory, sessionID: session.id }) + .then((x) => x.data) + .catch((err) => { + showToast({ + title: language.t("session.delete.failed.title"), + description: errorMessage(err), + }) + return false + }) + + if (!result) return + + setStore( + produce((draft) => { + const removed = new Set([session.id]) + const collect = (parentID: string) => { + for (const item of draft.session) { + if (item.parentID !== parentID) continue + removed.add(item.id) + collect(item.id) + } + } + collect(session.id) + draft.session = draft.session.filter((s) => !removed.has(s.id)) + }), + ) + + if (session.id === params.id) { + if (nextSession) { + navigate(`/${params.dir}/session/${nextSession.id}`) + } else { + navigate(`/${params.dir}/session`) + } + } + } + + command.register(() => { + const commands: CommandOption[] = [ + { + id: "sidebar.toggle", + title: language.t("command.sidebar.toggle"), + category: language.t("command.category.view"), + keybind: "mod+b", + onSelect: () => layout.sidebar.toggle(), + }, + { + id: "project.open", + title: language.t("command.project.open"), + category: language.t("command.category.project"), + keybind: "mod+o", + onSelect: () => chooseProject(), + }, + { + id: "provider.connect", + title: language.t("command.provider.connect"), + category: language.t("command.category.provider"), + onSelect: () => connectProvider(), + }, + { + id: "server.switch", + title: language.t("command.server.switch"), + category: language.t("command.category.server"), + onSelect: () => openServer(), + }, + { + id: "settings.open", + title: language.t("command.settings.open"), + category: language.t("command.category.settings"), + keybind: "mod+comma", + onSelect: () => openSettings(), + }, + { + id: "session.previous", + title: language.t("command.session.previous"), + category: language.t("command.category.session"), + keybind: "alt+arrowup", + onSelect: () => navigateSessionByOffset(-1), + }, + { + id: "session.next", + title: language.t("command.session.next"), + category: language.t("command.category.session"), + keybind: "alt+arrowdown", + onSelect: () => navigateSessionByOffset(1), + }, + { + id: "session.archive", + title: language.t("command.session.archive"), + category: language.t("command.category.session"), + keybind: "mod+shift+backspace", + disabled: !params.dir || !params.id, + onSelect: () => { + const session = currentSessions().find((s) => s.id === params.id) + if (session) archiveSession(session) + }, + }, + { + id: "theme.cycle", + title: language.t("command.theme.cycle"), + category: language.t("command.category.theme"), + keybind: "mod+shift+t", + onSelect: () => cycleTheme(1), + }, + ] + + for (const [id, definition] of availableThemeEntries()) { + commands.push({ + id: `theme.set.${id}`, + title: language.t("command.theme.set", { theme: definition.name ?? id }), + category: language.t("command.category.theme"), + onSelect: () => theme.commitPreview(), + onHighlight: () => { + theme.previewTheme(id) + return () => theme.cancelPreview() + }, + }) + } + + commands.push({ + id: "theme.scheme.cycle", + title: language.t("command.theme.scheme.cycle"), + category: language.t("command.category.theme"), + keybind: "mod+shift+s", + onSelect: () => cycleColorScheme(1), + }) + + for (const scheme of colorSchemeOrder) { + commands.push({ + id: `theme.scheme.${scheme}`, + title: language.t("command.theme.scheme.set", { scheme: colorSchemeLabel(scheme) }), + category: language.t("command.category.theme"), + onSelect: () => theme.commitPreview(), + onHighlight: () => { + theme.previewColorScheme(scheme) + return () => theme.cancelPreview() + }, + }) + } + + commands.push({ + id: "language.cycle", + title: language.t("command.language.cycle"), + category: language.t("command.category.language"), + onSelect: () => cycleLanguage(1), + }) + + for (const locale of language.locales) { + commands.push({ + id: `language.set.${locale}`, + title: language.t("command.language.set", { language: language.label(locale) }), + category: language.t("command.category.language"), + onSelect: () => setLocale(locale), + }) + } + + return commands + }) + + function connectProvider() { + dialog.show(() => ) + } + + function openServer() { + dialog.show(() => ) + } + + function openSettings() { + dialog.show(() => ) + } + + function navigateToProject(directory: string | undefined) { + if (!directory) return + server.projects.touch(directory) + const lastSession = store.lastSession[directory] + navigate(`/${base64Encode(directory)}${lastSession ? `/session/${lastSession}` : ""}`) + layout.mobileSidebar.hide() + } + + function navigateToSession(session: Session | undefined) { + if (!session) return + navigate(`/${base64Encode(session.directory)}/session/${session.id}`) + layout.mobileSidebar.hide() + } + + function openProject(directory: string, navigate = true) { + layout.projects.open(directory) + if (navigate) navigateToProject(directory) + } + + const displayName = (project: LocalProject) => project.name || getFilename(project.worktree) + + async function renameProject(project: LocalProject, next: string) { + if (!project.id) return + const current = displayName(project) + if (next === current) return + const name = next === getFilename(project.worktree) ? "" : next + await globalSDK.client.project.update({ projectID: project.id, directory: project.worktree, name }) + } + + async function renameSession(session: Session, next: string) { + if (next === session.title) return + await globalSDK.client.session.update({ + directory: session.directory, + sessionID: session.id, + title: next, + }) + } + + const renameWorkspace = (directory: string, next: string, projectId?: string, branch?: string) => { + const current = workspaceName(directory, projectId, branch) ?? branch ?? getFilename(directory) + if (current === next) return + setWorkspaceName(directory, next, projectId, branch) + } + + function closeProject(directory: string) { + const index = layout.projects.list().findIndex((x) => x.worktree === directory) + const next = layout.projects.list()[index + 1] + layout.projects.close(directory) + if (next) navigateToProject(next.worktree) + else navigate("/") + } + + async function chooseProject() { + function resolve(result: string | string[] | null) { + if (Array.isArray(result)) { + for (const directory of result) { + openProject(directory, false) + } + navigateToProject(result[0]) + } else if (result) { + openProject(result) + } + } + + if (platform.openDirectoryPickerDialog && server.isLocal()) { + const result = await platform.openDirectoryPickerDialog?.({ + title: language.t("command.project.open"), + multiple: true, + }) + resolve(result) + } else { + dialog.show( + () => , + () => resolve(null), + ) + } + } + + const errorMessage = (err: unknown) => { + if (err && typeof err === "object" && "data" in err) { + const data = (err as { data?: { message?: string } }).data + if (data?.message) return data.message + } + if (err instanceof Error) return err.message + return language.t("common.requestFailed") + } + + const deleteWorkspace = async (directory: string) => { + const current = currentProject() + if (!current) return + if (directory === current.worktree) return + + setBusy(directory, true) + + const result = await globalSDK.client.worktree + .remove({ directory: current.worktree, worktreeRemoveInput: { directory } }) + .then((x) => x.data) + .catch((err) => { + showToast({ + title: language.t("workspace.delete.failed.title"), + description: errorMessage(err), + }) + return false + }) + + setBusy(directory, false) + + if (!result) return + + layout.projects.close(directory) + layout.projects.open(current.worktree) + + if (params.dir && base64Decode(params.dir) === directory) { + navigateToProject(current.worktree) + } + } + + const resetWorkspace = async (directory: string) => { + const current = currentProject() + if (!current) return + if (directory === current.worktree) return + setBusy(directory, true) + + const progress = showToast({ + persistent: true, + title: language.t("workspace.resetting.title"), + description: language.t("workspace.resetting.description"), + }) + const dismiss = () => toaster.dismiss(progress) + + const sessions = await globalSDK.client.session + .list({ directory }) + .then((x) => x.data ?? []) + .catch(() => []) + + const result = await globalSDK.client.worktree + .reset({ directory: current.worktree, worktreeResetInput: { directory } }) + .then((x) => x.data) + .catch((err) => { + showToast({ + title: language.t("workspace.reset.failed.title"), + description: errorMessage(err), + }) + return false + }) + + if (!result) { + setBusy(directory, false) + dismiss() + return + } + + const archivedAt = Date.now() + await Promise.all( + sessions + .filter((session) => session.time.archived === undefined) + .map((session) => + globalSDK.client.session + .update({ + sessionID: session.id, + directory: session.directory, + time: { archived: archivedAt }, + }) + .catch(() => undefined), + ), + ) + + await globalSDK.client.instance.dispose({ directory }).catch(() => undefined) + + setBusy(directory, false) + dismiss() + + showToast({ + title: language.t("workspace.reset.success.title"), + description: language.t("workspace.reset.success.description"), + actions: [ + { + label: language.t("command.session.new"), + onClick: () => { + const href = `/${base64Encode(directory)}/session` + navigate(href) + layout.mobileSidebar.hide() + }, + }, + { + label: language.t("common.dismiss"), + onClick: "dismiss", + }, + ], + }) + } + + function DialogDeleteSession(props: { session: Session }) { + const handleDelete = async () => { + await deleteSession(props.session) + dialog.close() + } + + return ( + +
+
+ + {language.t("session.delete.confirm", { name: props.session.title })} + +
+
+ + +
+
+
+ ) + } + + function DialogDeleteWorkspace(props: { directory: string }) { + const name = createMemo(() => getFilename(props.directory)) + const [data, setData] = createStore({ + status: "loading" as "loading" | "ready" | "error", + dirty: false, + }) + + onMount(() => { + const current = currentProject() + if (!current) { + setData({ status: "error", dirty: false }) + return + } + + globalSDK.client.file + .status({ directory: props.directory }) + .then((x) => { + const files = x.data ?? [] + const dirty = files.length > 0 + setData({ status: "ready", dirty }) + }) + .catch(() => { + setData({ status: "error", dirty: false }) + }) + }) + + const handleDelete = async () => { + await deleteWorkspace(props.directory) + dialog.close() + } + + const description = () => { + if (data.status === "loading") return language.t("workspace.status.checking") + if (data.status === "error") return language.t("workspace.status.error") + if (!data.dirty) return language.t("workspace.status.clean") + return language.t("workspace.status.dirty") + } + + return ( + +
+
+ + {language.t("workspace.delete.confirm", { name: name() })} + + {description()} +
+
+ + +
+
+
+ ) + } + + function DialogResetWorkspace(props: { directory: string }) { + const name = createMemo(() => getFilename(props.directory)) + const [state, setState] = createStore({ + status: "loading" as "loading" | "ready" | "error", + dirty: false, + sessions: [] as Session[], + }) + + const refresh = async () => { + const sessions = await globalSDK.client.session + .list({ directory: props.directory }) + .then((x) => x.data ?? []) + .catch(() => []) + const active = sessions.filter((session) => session.time.archived === undefined) + setState({ sessions: active }) + } + + onMount(() => { + const current = currentProject() + if (!current) { + setState({ status: "error", dirty: false }) + return + } + + globalSDK.client.file + .status({ directory: props.directory }) + .then((x) => { + const files = x.data ?? [] + const dirty = files.length > 0 + setState({ status: "ready", dirty }) + void refresh() + }) + .catch(() => { + setState({ status: "error", dirty: false }) + }) + }) + + const handleReset = () => { + dialog.close() + void resetWorkspace(props.directory) + } + + const archivedCount = () => state.sessions.length + + const description = () => { + if (state.status === "loading") return language.t("workspace.status.checking") + if (state.status === "error") return language.t("workspace.status.error") + if (!state.dirty) return language.t("workspace.status.clean") + return language.t("workspace.status.dirty") + } + + const archivedLabel = () => { + const count = archivedCount() + if (count === 0) return language.t("workspace.reset.archived.none") + if (count === 1) return language.t("workspace.reset.archived.one") + return language.t("workspace.reset.archived.many", { count }) + } + + return ( + +
+
+ + {language.t("workspace.reset.confirm", { name: name() })} + + + {description()} {archivedLabel()} {language.t("workspace.reset.note")} + +
+
+ + +
+
+
+ ) + } + + createEffect( + on( + () => ({ ready: pageReady(), dir: params.dir, id: params.id }), + (value) => { + if (!value.ready) return + const dir = value.dir + const id = value.id + if (!dir || !id) return + const directory = base64Decode(dir) + setStore("lastSession", directory, id) + notification.session.markViewed(id) + const expanded = untrack(() => store.workspaceExpanded[directory]) + if (expanded === false) { + setStore("workspaceExpanded", directory, true) + } + requestAnimationFrame(() => scrollToSession(id, `${directory}:${id}`)) + }, + { defer: true }, + ), + ) + + createEffect(() => { + const project = currentProject() + if (!project) return + + if (workspaceSetting()) { + const activeDir = params.dir ? base64Decode(params.dir) : "" + const dirs = [project.worktree, ...(project.sandboxes ?? [])] + for (const directory of dirs) { + const expanded = store.workspaceExpanded[directory] ?? directory === project.worktree + const active = directory === activeDir + if (!expanded && !active) continue + globalSync.project.loadSessions(directory) + } + return + } + + globalSync.project.loadSessions(project.worktree) + }) + + function getDraggableId(event: unknown): string | undefined { + if (typeof event !== "object" || event === null) return undefined + if (!("draggable" in event)) return undefined + const draggable = (event as { draggable?: { id?: unknown } }).draggable + if (!draggable) return undefined + return typeof draggable.id === "string" ? draggable.id : undefined + } + + function handleDragStart(event: unknown) { + const id = getDraggableId(event) + if (!id) return + setStore("activeProject", id) + } + + function handleDragOver(event: DragEvent) { + const { draggable, droppable } = event + if (draggable && droppable) { + const projects = layout.projects.list() + const fromIndex = projects.findIndex((p) => p.worktree === draggable.id.toString()) + const toIndex = projects.findIndex((p) => p.worktree === droppable.id.toString()) + if (fromIndex !== toIndex && toIndex !== -1) { + layout.projects.move(draggable.id.toString(), toIndex) + } + } + } + + function handleDragEnd() { + setStore("activeProject", undefined) + } + + function workspaceIds(project: LocalProject | undefined) { + if (!project) return [] + const dirs = [project.worktree, ...(project.sandboxes ?? [])] + const active = currentProject() + const directory = active?.worktree === project.worktree && params.dir ? base64Decode(params.dir) : undefined + const next = directory && directory !== project.worktree && !dirs.includes(directory) ? [...dirs, directory] : dirs + + const existing = store.workspaceOrder[project.worktree] + if (!existing) return next + + const keep = existing.filter((d) => next.includes(d)) + const missing = next.filter((d) => !existing.includes(d)) + return [...keep, ...missing] + } + + function handleWorkspaceDragStart(event: unknown) { + const id = getDraggableId(event) + if (!id) return + setStore("activeWorkspace", id) + } + + function handleWorkspaceDragOver(event: DragEvent) { + const { draggable, droppable } = event + if (!draggable || !droppable) return + + const project = currentProject() + if (!project) return + + const ids = workspaceIds(project) + const fromIndex = ids.findIndex((dir) => dir === draggable.id.toString()) + const toIndex = ids.findIndex((dir) => dir === droppable.id.toString()) + if (fromIndex === -1 || toIndex === -1) return + if (fromIndex === toIndex) return + + const result = ids.slice() + const [item] = result.splice(fromIndex, 1) + if (!item) return + result.splice(toIndex, 0, item) + setStore("workspaceOrder", project.worktree, result) + } + + function handleWorkspaceDragEnd() { + setStore("activeWorkspace", undefined) + } + + const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => { + const notification = useNotification() + const notifications = createMemo(() => notification.project.unseen(props.project.worktree)) + const hasError = createMemo(() => notifications().some((n) => n.type === "error")) + const name = createMemo(() => props.project.name || getFilename(props.project.worktree)) + const mask = "radial-gradient(circle 5px at calc(100% - 4px) 4px, transparent 5px, black 5.5px)" + const opencode = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750" + + return ( +
+
+ 0 && props.notify + ? { "-webkit-mask-image": mask, "mask-image": mask } + : undefined + } + /> +
+ 0 && props.notify}> +
+ +
+ ) + } + + const SessionItem = (props: { + session: Session + slug: string + mobile?: boolean + dense?: boolean + popover?: boolean + }): JSX.Element => { + const notification = useNotification() + const notifications = createMemo(() => notification.session.unseen(props.session.id)) + const hasError = createMemo(() => notifications().some((n) => n.type === "error")) + const [sessionStore] = globalSync.child(props.session.directory) + const hasPermissions = createMemo(() => { + const permissions = sessionStore.permission?.[props.session.id] ?? [] + if (permissions.length > 0) return true + const childSessions = sessionStore.session.filter((s) => s.parentID === props.session.id) + for (const child of childSessions) { + const childPermissions = sessionStore.permission?.[child.id] ?? [] + if (childPermissions.length > 0) return true + } + return false + }) + const isWorking = createMemo(() => { + if (hasPermissions()) return false + const status = sessionStore.session_status[props.session.id] + return status?.type === "busy" || status?.type === "retry" + }) + + const tint = createMemo(() => { + const messages = sessionStore.message[props.session.id] + if (!messages) return undefined + const user = messages + .slice() + .reverse() + .find((m) => m.role === "user") + if (!user?.agent) return undefined + + const agent = sessionStore.agent.find((a) => a.name === user.agent) + return agent?.color + }) + + const hoverMessages = createMemo(() => + sessionStore.message[props.session.id]?.filter((message) => message.role === "user"), + ) + const hoverReady = createMemo(() => sessionStore.message[props.session.id] !== undefined) + const hoverAllowed = createMemo(() => !props.mobile && layout.sidebar.opened()) + const hoverEnabled = createMemo(() => (props.popover ?? true) && hoverAllowed()) + const isActive = createMemo(() => props.session.id === params.id) + const [menuOpen, setMenuOpen] = createSignal(false) + const [pendingRename, setPendingRename] = createSignal(false) + + const messageLabel = (message: Message) => { + const parts = sessionStore.part[message.id] ?? [] + const text = parts.find((part): part is TextPart => part?.type === "text" && !part.synthetic && !part.ignored) + return text?.text + } + + const item = ( + prefetchSession(props.session, "high")} + onFocus={() => prefetchSession(props.session, "high")} + onClick={() => setHoverSession(undefined)} + > +
+
+ }> + + + + +
+ + +
+ + 0}> +
+ + +
+ props.session.title} + onSave={(next) => renameSession(props.session, next)} + class="text-14-regular text-text-strong grow-1 min-w-0 overflow-hidden text-ellipsis truncate" + displayClass="text-14-regular text-text-strong grow-1 min-w-0 overflow-hidden text-ellipsis truncate" + stopPropagation + /> + + {(summary) => ( +
+ +
+ )} +
+
+
+ ) + + return ( +
+ + {item} + + } + > + setHoverSession(open ? props.session.id : undefined)} + > + {language.t("session.messages.loading")}
} + > +
+ { + if (!isActive()) { + sessionStorage.setItem("opencode.pendingMessage", `${props.session.id}|${message.id}`) + navigate(`${props.slug}/session/${props.session.id}`) + return + } + window.history.replaceState(null, "", `#message-${message.id}`) + window.dispatchEvent(new HashChangeEvent("hashchange")) + }} + size="normal" + class="w-60" + /> +
+ + + +
+ + + + + + { + if (!pendingRename()) return + event.preventDefault() + setPendingRename(false) + openEditor(`session:${props.session.id}`, props.session.title) + }} + > + { + setPendingRename(true) + setMenuOpen(false) + }} + > + {language.t("common.rename")} + + archiveSession(props.session)}> + {language.t("common.archive")} + + + dialog.show(() => )}> + {language.t("common.delete")} + + + + +
+
+ ) + } + + const NewSessionItem = (props: { slug: string; mobile?: boolean; dense?: boolean }): JSX.Element => { + const label = language.t("command.session.new") + const tooltip = () => props.mobile || !layout.sidebar.opened() + const item = ( + setHoverSession(undefined)} + > +
+
+ +
+ + {label} + +
+
+ ) + + return ( +
+ + {item} + + } + > + {item} + +
+ ) + } + + const SessionSkeleton = (props: { count?: number }): JSX.Element => { + const items = Array.from({ length: props.count ?? 4 }, (_, index) => index) + return ( +
+ + {() =>
} + +
+ ) + } + + const ProjectDragOverlay = (): JSX.Element => { + const project = createMemo(() => layout.projects.list().find((p) => p.worktree === store.activeProject)) + return ( + + {(p) => ( +
+ +
+ )} +
+ ) + } + + const WorkspaceDragOverlay = (): JSX.Element => { + const label = createMemo(() => { + const project = currentProject() + if (!project) return + const directory = store.activeWorkspace + if (!directory) return + + const [workspaceStore] = globalSync.child(directory) + const kind = + directory === project.worktree ? language.t("workspace.type.local") : language.t("workspace.type.sandbox") + const name = workspaceLabel(directory, workspaceStore.vcs?.branch, project.id) + return `${kind} : ${name}` + }) + + return ( + + {(value) => ( +
{value()}
+ )} +
+ ) + } + + const SortableWorkspace = (props: { directory: string; project: LocalProject; mobile?: boolean }): JSX.Element => { + const sortable = createSortable(props.directory) + const [workspaceStore, setWorkspaceStore] = globalSync.child(props.directory, { bootstrap: false }) + const [menuOpen, setMenuOpen] = createSignal(false) + const [pendingRename, setPendingRename] = createSignal(false) + const slug = createMemo(() => base64Encode(props.directory)) + const sessions = createMemo(() => + workspaceStore.session + .filter((session) => session.directory === workspaceStore.path.directory) + .filter((session) => !session.parentID && !session.time?.archived) + .toSorted(sortSessions), + ) + const local = createMemo(() => props.directory === props.project.worktree) + const active = createMemo(() => { + const current = params.dir ? base64Decode(params.dir) : "" + return current === props.directory + }) + const workspaceValue = createMemo(() => { + const branch = workspaceStore.vcs?.branch + const name = branch ?? getFilename(props.directory) + return workspaceName(props.directory, props.project.id, branch) ?? name + }) + const open = createMemo(() => store.workspaceExpanded[props.directory] ?? local()) + const boot = createMemo(() => open() || active()) + const loading = createMemo(() => open() && workspaceStore.status !== "complete" && sessions().length === 0) + const hasMore = createMemo(() => local() && workspaceStore.sessionTotal > workspaceStore.session.length) + const busy = createMemo(() => isBusy(props.directory)) + const loadMore = async () => { + if (!local()) return + setWorkspaceStore("limit", (limit) => limit + 5) + await globalSync.project.loadSessions(props.directory) + } + + const workspaceEditActive = createMemo(() => editorOpen(`workspace:${props.directory}`)) + + const openWrapper = (value: boolean) => { + setStore("workspaceExpanded", props.directory, value) + if (value) return + if (editorOpen(`workspace:${props.directory}`)) closeEditor() + } + + createEffect(() => { + if (!boot()) return + globalSync.child(props.directory, { bootstrap: true }) + }) + + const header = () => ( +
+
+ }> + + +
+ + {local() ? language.t("workspace.type.local") : language.t("workspace.type.sandbox")} : + + + {workspaceStore.vcs?.branch ?? getFilename(props.directory)} + + } + > + { + const trimmed = next.trim() + if (!trimmed) return + renameWorkspace(props.directory, trimmed, props.project.id, workspaceStore.vcs?.branch) + setEditor("value", workspaceValue()) + }} + class="text-14-medium text-text-base min-w-0 truncate" + displayClass="text-14-medium text-text-base min-w-0 truncate" + editing={workspaceEditActive()} + stopPropagation={false} + openOnDblClick={false} + /> + + +
+ ) + + return ( +
+ +
+
+
+ + {header()} + + } + > +
{header()}
+
+
+ + + + + + { + if (!pendingRename()) return + event.preventDefault() + setPendingRename(false) + openEditor(`workspace:${props.directory}`, workspaceValue()) + }} + > + { + setPendingRename(true) + setMenuOpen(false) + }} + > + {language.t("common.rename")} + + dialog.show(() => )} + > + {language.t("common.reset")} + + dialog.show(() => )} + > + {language.t("common.delete")} + + + + +
+
+
+
+ + + + +
+
+ ) + } + + const SortableProject = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => { + const sortable = createSortable(props.project.worktree) + const selected = createMemo(() => { + const current = params.dir ? base64Decode(params.dir) : "" + return props.project.worktree === current || props.project.sandboxes?.includes(current) + }) + + const workspaces = createMemo(() => workspaceIds(props.project).slice(0, 2)) + const workspaceEnabled = createMemo(() => layout.sidebar.workspaces(props.project.worktree)()) + const [open, setOpen] = createSignal(false) + + const label = (directory: string) => { + const [data] = globalSync.child(directory) + const kind = + directory === props.project.worktree ? language.t("workspace.type.local") : language.t("workspace.type.sandbox") + const name = workspaceLabel(directory, data.vcs?.branch, props.project.id) + return `${kind} : ${name}` + } + + const sessions = (directory: string) => { + const [data] = globalSync.child(directory) + return data.session + .filter((session) => session.directory === data.path.directory) + .filter((session) => !session.parentID && !session.time?.archived) + .toSorted(sortSessions) + .slice(0, 2) + } + + const projectSessions = () => { + const [data] = globalSync.child(props.project.worktree) + return data.session + .filter((session) => session.directory === data.path.directory) + .filter((session) => !session.parentID && !session.time?.archived) + .toSorted(sortSessions) + .slice(0, 2) + } + + const projectName = () => props.project.name || getFilename(props.project.worktree) + const trigger = ( + + ) + + return ( + // @ts-ignore +
+ { + setOpen(value) + if (value) setHoverSession(undefined) + }} + > +
+
+
{displayName(props.project)}
+ + { + event.stopPropagation() + setOpen(false) + closeProject(props.project.worktree) + }} + /> + +
+
{language.t("sidebar.project.recentSessions")}
+
+ + {(session) => ( + + )} + + } + > + + {(directory) => ( +
+
+
+ +
+ {label(directory)} +
+ + {(session) => ( + + )} + +
+ )} +
+
+
+
+ +
+
+
+
+ ) + } + + const LocalWorkspace = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => { + const [workspaceStore, setWorkspaceStore] = globalSync.child(props.project.worktree) + const slug = createMemo(() => base64Encode(props.project.worktree)) + const sessions = createMemo(() => + workspaceStore.session + .filter((session) => session.directory === workspaceStore.path.directory) + .filter((session) => !session.parentID && !session.time?.archived) + .toSorted(sortSessions), + ) + const loading = createMemo(() => workspaceStore.status !== "complete" && sessions().length === 0) + const hasMore = createMemo(() => workspaceStore.sessionTotal > workspaceStore.session.length) + const loadMore = async () => { + setWorkspaceStore("limit", (limit) => limit + 5) + await globalSync.project.loadSessions(props.project.worktree) + } + + return ( +
{ + if (!props.mobile) scrollContainerRef = el + }} + class="size-full flex flex-col py-2 overflow-y-auto no-scrollbar" + style={{ "overflow-anchor": "none" }} + > + +
+ ) + } + + const SidebarContent = (sidebarProps: { mobile?: boolean }) => { + const expanded = () => sidebarProps.mobile || layout.sidebar.opened() + + const sync = useGlobalSync() + const project = createMemo(() => currentProject()) + const projectName = createMemo(() => { + const current = project() + if (!current) return "" + return current.name || getFilename(current.worktree) + }) + const projectId = createMemo(() => project()?.id ?? "") + const workspaces = createMemo(() => workspaceIds(project())) + + const createWorkspace = async () => { + const current = project() + if (!current) return + + const created = await globalSDK.client.worktree + .create({ directory: current.worktree }) + .then((x) => x.data) + .catch((err) => { + showToast({ + title: language.t("workspace.create.failed.title"), + description: errorMessage(err), + }) + return undefined + }) + + if (!created?.directory) return + + globalSync.child(created.directory) + navigate(`/${base64Encode(created.directory)}/session`) + } + + command.register(() => [ + { + id: "workspace.new", + title: language.t("workspace.new"), + category: language.t("command.category.workspace"), + keybind: "mod+shift+w", + disabled: !layout.sidebar.workspaces(project()?.worktree ?? "")(), + onSelect: createWorkspace, + }, + ]) + + const homedir = createMemo(() => sync.data.path.home) + + return ( +
+
+
+ + + +
+ p.worktree)}> + + {(project) => } + + + + {language.t("command.project.open")} + + {command.keybind("project.open")} + +
+ } + > + + +
+ + + + +
+
+ + + + + platform.openLink("https://opencode.ai/desktop-feedback")} + aria-label={language.t("sidebar.help")} + /> + +
+
+ + +
+ + {(p) => ( + <> +
+
+
+ project() && renameProject(project()!, next)} + class="text-16-medium text-text-strong truncate" + displayClass="text-16-medium text-text-strong truncate" + stopPropagation + /> + + + + {project()?.worktree.replace(homedir(), "~")} + + +
+ + + + + + dialog.show(() => )}> + {language.t("common.edit")} + + layout.sidebar.toggleWorkspaces(p.worktree)}> + + {layout.sidebar.workspaces(p.worktree)() + ? language.t("sidebar.workspaces.disable") + : language.t("sidebar.workspaces.enable")} + + + + closeProject(p.worktree)}> + {language.t("common.close")} + + + + +
+
+ + +
+ + + +
+
+ +
+ + } + > + <> +
+ + + +
+
+ + + +
{ + if (!sidebarProps.mobile) scrollContainerRef = el + }} + class="size-full flex flex-col py-2 gap-4 overflow-y-auto no-scrollbar" + style={{ "overflow-anchor": "none" }} + > + + + {(directory) => ( + + )} + + +
+ + + +
+
+ +
+ + )} +
+ 0 && providers.paid().length === 0}> +
+
+
+
{language.t("sidebar.gettingStarted.title")}
+
{language.t("sidebar.gettingStarted.line1")}
+
{language.t("sidebar.gettingStarted.line2")}
+
+ +
+
+
+
+
+
+ ) + } + + return ( +
+ +
+ +
+
{ + if (e.target === e.currentTarget) layout.mobileSidebar.hide() + }} + /> + +
+ +
+ }> + {props.children} + +
+
+ +
+ ) +} diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx new file mode 100644 index 00000000000..719e13f0052 --- /dev/null +++ b/packages/app/src/pages/session.tsx @@ -0,0 +1,2150 @@ +import { + For, + Index, + onCleanup, + onMount, + Show, + Match, + Switch, + createMemo, + createEffect, + on, + createSignal, +} from "solid-js" +import { createMediaQuery } from "@solid-primitives/media" +import { createResizeObserver } from "@solid-primitives/resize-observer" +import { Dynamic } from "solid-js/web" +import { useLocal } from "@/context/local" +import { selectionFromLines, useFile, type SelectedLineRange } from "@/context/file" +import { createStore } from "solid-js/store" +import { PromptInput } from "@/components/prompt-input" +import { SessionContextUsage } from "@/components/session-context-usage" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { DiffChanges } from "@opencode-ai/ui/diff-changes" +import { ResizeHandle } from "@opencode-ai/ui/resize-handle" +import { Tabs } from "@opencode-ai/ui/tabs" +import { useCodeComponent } from "@opencode-ai/ui/context/code" +import { SessionTurn } from "@opencode-ai/ui/session-turn" +import { createAutoScroll } from "@opencode-ai/ui/hooks" +import { SessionReview } from "@opencode-ai/ui/session-review" +import { Mark } from "@opencode-ai/ui/logo" + +import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, closestCenter } from "@thisbeyond/solid-dnd" +import type { DragEvent } from "@thisbeyond/solid-dnd" +import { useSync } from "@/context/sync" +import { useTerminal, type LocalPTY } from "@/context/terminal" +import { useLayout } from "@/context/layout" +import { Terminal } from "@/components/terminal" +import { checksum, base64Encode, base64Decode } from "@opencode-ai/util/encode" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { DialogSelectFile } from "@/components/dialog-select-file" +import { DialogSelectModel } from "@/components/dialog-select-model" +import { DialogSelectMcp } from "@/components/dialog-select-mcp" +import { DialogFork } from "@/components/dialog-fork" +import { useCommand } from "@/context/command" +import { useLanguage } from "@/context/language" +import { useNavigate, useParams } from "@solidjs/router" +import { UserMessage } from "@opencode-ai/sdk/v2" +import type { FileDiff } from "@opencode-ai/sdk/v2/client" +import { useSDK } from "@/context/sdk" +import { usePrompt } from "@/context/prompt" +import { extractPromptFromParts } from "@/utils/prompt" +import { ConstrainDragYAxis, getDraggableId } from "@/utils/solid-dnd" +import { usePermission } from "@/context/permission" +import { showToast } from "@opencode-ai/ui/toast" +import { + SessionHeader, + SessionContextTab, + SortableTab, + FileVisual, + SortableTerminalTab, + NewSessionView, +} from "@/components/session" +import { usePlatform } from "@/context/platform" +import { navMark, navParams } from "@/utils/perf" +import { same } from "@/utils/same" + +type DiffStyle = "unified" | "split" + +const handoff = { + prompt: "", + terminals: [] as string[], + files: {} as Record, +} + +interface SessionReviewTabProps { + diffs: () => FileDiff[] + view: () => ReturnType["view"]> + diffStyle: DiffStyle + onDiffStyleChange?: (style: DiffStyle) => void + onViewFile?: (file: string) => void + classes?: { + root?: string + header?: string + container?: string + } +} + +function SessionReviewTab(props: SessionReviewTabProps) { + let scroll: HTMLDivElement | undefined + let frame: number | undefined + let pending: { x: number; y: number } | undefined + + const sdk = useSDK() + + const readFile = (path: string) => { + return sdk.client.file + .read({ path }) + .then((x) => x.data) + .catch(() => undefined) + } + + const restoreScroll = (retries = 0) => { + const el = scroll + if (!el) return + + const s = props.view().scroll("review") + if (!s) return + + // Wait for content to be scrollable - content may not have rendered yet + if (el.scrollHeight <= el.clientHeight && retries < 10) { + requestAnimationFrame(() => restoreScroll(retries + 1)) + return + } + + if (el.scrollTop !== s.y) el.scrollTop = s.y + if (el.scrollLeft !== s.x) el.scrollLeft = s.x + } + + const handleScroll = (event: Event & { currentTarget: HTMLDivElement }) => { + pending = { + x: event.currentTarget.scrollLeft, + y: event.currentTarget.scrollTop, + } + if (frame !== undefined) return + + frame = requestAnimationFrame(() => { + frame = undefined + + const next = pending + pending = undefined + if (!next) return + + props.view().setScroll("review", next) + }) + } + + createEffect( + on( + () => props.diffs().length, + () => { + requestAnimationFrame(restoreScroll) + }, + { defer: true }, + ), + ) + + onCleanup(() => { + if (frame === undefined) return + cancelAnimationFrame(frame) + }) + + return ( + { + scroll = el + restoreScroll() + }} + onScroll={handleScroll} + open={props.view().review.open()} + onOpenChange={props.view().review.setOpen} + classes={{ + root: props.classes?.root ?? "pb-40", + header: props.classes?.header ?? "px-6", + container: props.classes?.container ?? "px-6", + }} + diffs={props.diffs()} + diffStyle={props.diffStyle} + onDiffStyleChange={props.onDiffStyleChange} + onViewFile={props.onViewFile} + readFile={readFile} + /> + ) +} + +export default function Page() { + const layout = useLayout() + const local = useLocal() + const file = useFile() + const sync = useSync() + const terminal = useTerminal() + const dialog = useDialog() + const codeComponent = useCodeComponent() + const command = useCommand() + const language = useLanguage() + const platform = usePlatform() + const params = useParams() + const navigate = useNavigate() + const sdk = useSDK() + const prompt = usePrompt() + const permission = usePermission() + const [pendingMessage, setPendingMessage] = createSignal(undefined) + const [pendingHash, setPendingHash] = createSignal(undefined) + const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) + const tabs = createMemo(() => layout.tabs(sessionKey())) + const view = createMemo(() => layout.view(sessionKey())) + + if (import.meta.env.DEV) { + createEffect( + on( + () => [params.dir, params.id] as const, + ([dir, id], prev) => { + if (!id) return + navParams({ dir, from: prev?.[1], to: id }) + }, + ), + ) + + createEffect(() => { + const id = params.id + if (!id) return + if (!prompt.ready()) return + navMark({ dir: params.dir, to: id, name: "storage:prompt-ready" }) + }) + + createEffect(() => { + const id = params.id + if (!id) return + if (!terminal.ready()) return + navMark({ dir: params.dir, to: id, name: "storage:terminal-ready" }) + }) + + createEffect(() => { + const id = params.id + if (!id) return + if (!file.ready()) return + navMark({ dir: params.dir, to: id, name: "storage:file-view-ready" }) + }) + + createEffect(() => { + const id = params.id + if (!id) return + if (sync.data.message[id] === undefined) return + navMark({ dir: params.dir, to: id, name: "session:data-ready" }) + }) + } + + const isDesktop = createMediaQuery("(min-width: 768px)") + + function normalizeTab(tab: string) { + if (!tab.startsWith("file://")) return tab + return file.tab(tab) + } + + function normalizeTabs(list: string[]) { + const seen = new Set() + const next: string[] = [] + for (const item of list) { + const value = normalizeTab(item) + if (seen.has(value)) continue + seen.add(value) + next.push(value) + } + return next + } + + const openTab = (value: string) => { + const next = normalizeTab(value) + tabs().open(next) + + const path = file.pathFromTab(next) + if (path) file.load(path) + } + + createEffect(() => { + const active = tabs().active() + if (!active) return + + const path = file.pathFromTab(active) + if (path) file.load(path) + }) + + createEffect(() => { + const current = tabs().all() + if (current.length === 0) return + + const next = normalizeTabs(current) + if (same(current, next)) return + + tabs().setAll(next) + + const active = tabs().active() + if (!active) return + if (!active.startsWith("file://")) return + + const normalized = normalizeTab(active) + if (active === normalized) return + tabs().setActive(normalized) + }) + + const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) + const reviewCount = createMemo(() => info()?.summary?.files ?? 0) + const hasReview = createMemo(() => reviewCount() > 0) + const revertMessageID = createMemo(() => info()?.revert?.messageID) + const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : [])) + const messagesReady = createMemo(() => { + const id = params.id + if (!id) return true + return sync.data.message[id] !== undefined + }) + const historyMore = createMemo(() => { + const id = params.id + if (!id) return false + return sync.session.history.more(id) + }) + const historyLoading = createMemo(() => { + const id = params.id + if (!id) return false + return sync.session.history.loading(id) + }) + const emptyUserMessages: UserMessage[] = [] + const userMessages = createMemo(() => messages().filter((m) => m.role === "user") as UserMessage[], emptyUserMessages) + const visibleUserMessages = createMemo(() => { + const revert = revertMessageID() + if (!revert) return userMessages() + return userMessages().filter((m) => m.id < revert) + }, emptyUserMessages) + const lastUserMessage = createMemo(() => visibleUserMessages().at(-1)) + + createEffect( + on( + () => lastUserMessage()?.id, + () => { + const msg = lastUserMessage() + if (!msg) return + if (msg.agent) local.agent.set(msg.agent) + if (msg.model) local.model.set(msg.model) + }, + ), + ) + + const [store, setStore] = createStore({ + activeDraggable: undefined as string | undefined, + activeTerminalDraggable: undefined as string | undefined, + expanded: {} as Record, + messageId: undefined as string | undefined, + turnStart: 0, + mobileTab: "session" as "session" | "review", + newSessionWorktree: "main", + promptHeight: 0, + }) + + const renderedUserMessages = createMemo(() => { + const msgs = visibleUserMessages() + const start = store.turnStart + if (start <= 0) return msgs + if (start >= msgs.length) return emptyUserMessages + return msgs.slice(start) + }, emptyUserMessages) + + const newSessionWorktree = createMemo(() => { + if (store.newSessionWorktree === "create") return "create" + const project = sync.project + if (project && sync.data.path.directory !== project.worktree) return sync.data.path.directory + return "main" + }) + + const activeMessage = createMemo(() => { + if (!store.messageId) return lastUserMessage() + const found = visibleUserMessages()?.find((m) => m.id === store.messageId) + return found ?? lastUserMessage() + }) + const setActiveMessage = (message: UserMessage | undefined) => { + setStore("messageId", message?.id) + } + + function navigateMessageByOffset(offset: number) { + const msgs = visibleUserMessages() + if (msgs.length === 0) return + + const current = activeMessage() + const currentIndex = current ? msgs.findIndex((m) => m.id === current.id) : -1 + const targetIndex = currentIndex === -1 ? (offset > 0 ? 0 : msgs.length - 1) : currentIndex + offset + if (targetIndex < 0 || targetIndex >= msgs.length) return + + scrollToMessage(msgs[targetIndex], "auto") + } + + const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : [])) + const diffsReady = createMemo(() => { + const id = params.id + if (!id) return true + if (!hasReview()) return true + return sync.data.session_diff[id] !== undefined + }) + + const idle = { type: "idle" as const } + let inputRef!: HTMLDivElement + let promptDock: HTMLDivElement | undefined + let scroller: HTMLDivElement | undefined + + const [scrollGesture, setScrollGesture] = createSignal(0) + const scrollGestureWindowMs = 250 + + const markScrollGesture = (target?: EventTarget | null) => { + const root = scroller + if (!root) return + + const el = target instanceof Element ? target : undefined + const nested = el?.closest("[data-scrollable]") + if (nested && nested !== root) return + + setScrollGesture(Date.now()) + } + + const hasScrollGesture = () => Date.now() - scrollGesture() < scrollGestureWindowMs + + createEffect(() => { + if (!params.id) return + sync.session.sync(params.id) + }) + + const [autoCreated, setAutoCreated] = createSignal(false) + + createEffect(() => { + if (!view().terminal.opened()) { + setAutoCreated(false) + return + } + if (!terminal.ready() || terminal.all().length !== 0 || autoCreated()) return + terminal.new() + setAutoCreated(true) + }) + + createEffect( + on( + () => terminal.all().length, + (count, prevCount) => { + if (prevCount !== undefined && prevCount > 0 && count === 0) { + if (view().terminal.opened()) { + view().terminal.toggle() + } + } + }, + ), + ) + + createEffect( + on( + () => terminal.active(), + (activeId) => { + if (!activeId || !view().terminal.opened()) return + // Immediately remove focus + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur() + } + const wrapper = document.getElementById(`terminal-wrapper-${activeId}`) + const element = wrapper?.querySelector('[data-component="terminal"]') as HTMLElement + if (!element) return + + // Find and focus the ghostty textarea (the actual input element) + const textarea = element.querySelector("textarea") as HTMLTextAreaElement + if (textarea) { + textarea.focus() + return + } + // Fallback: focus container and dispatch pointer event + element.focus() + element.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true })) + }, + ), + ) + + createEffect( + on( + () => visibleUserMessages().at(-1)?.id, + (lastId, prevLastId) => { + if (lastId && prevLastId && lastId > prevLastId) { + setStore("messageId", undefined) + } + }, + { defer: true }, + ), + ) + + const status = createMemo(() => sync.data.session_status[params.id ?? ""] ?? idle) + + createEffect( + on( + () => params.id, + () => { + setStore("messageId", undefined) + setStore("expanded", {}) + }, + { defer: true }, + ), + ) + + createEffect(() => { + const id = lastUserMessage()?.id + if (!id) return + setStore("expanded", id, status().type !== "idle") + }) + + command.register(() => [ + { + id: "session.new", + title: language.t("command.session.new"), + category: language.t("command.category.session"), + keybind: "mod+shift+s", + slash: "new", + onSelect: () => navigate(`/${params.dir}/session`), + }, + { + id: "file.open", + title: language.t("command.file.open"), + description: language.t("command.file.open.description"), + category: language.t("command.category.file"), + keybind: "mod+p", + slash: "open", + onSelect: () => dialog.show(() => ), + }, + { + id: "terminal.toggle", + title: language.t("command.terminal.toggle"), + description: "", + category: language.t("command.category.view"), + keybind: "ctrl+`", + slash: "terminal", + onSelect: () => view().terminal.toggle(), + }, + { + id: "review.toggle", + title: language.t("command.review.toggle"), + description: "", + category: language.t("command.category.view"), + keybind: "mod+shift+r", + onSelect: () => view().reviewPanel.toggle(), + }, + { + id: "terminal.new", + title: language.t("command.terminal.new"), + description: language.t("command.terminal.new.description"), + category: language.t("command.category.terminal"), + keybind: "ctrl+alt+t", + onSelect: () => { + if (terminal.all().length > 0) terminal.new() + view().terminal.open() + }, + }, + { + id: "steps.toggle", + title: language.t("command.steps.toggle"), + description: language.t("command.steps.toggle.description"), + category: language.t("command.category.view"), + keybind: "mod+e", + slash: "steps", + disabled: !params.id, + onSelect: () => { + const msg = activeMessage() + if (!msg) return + setStore("expanded", msg.id, (open: boolean | undefined) => !open) + }, + }, + { + id: "message.previous", + title: language.t("command.message.previous"), + description: language.t("command.message.previous.description"), + category: language.t("command.category.session"), + keybind: "mod+arrowup", + disabled: !params.id, + onSelect: () => navigateMessageByOffset(-1), + }, + { + id: "message.next", + title: language.t("command.message.next"), + description: language.t("command.message.next.description"), + category: language.t("command.category.session"), + keybind: "mod+arrowdown", + disabled: !params.id, + onSelect: () => navigateMessageByOffset(1), + }, + { + id: "model.choose", + title: language.t("command.model.choose"), + description: language.t("command.model.choose.description"), + category: language.t("command.category.model"), + keybind: "mod+'", + slash: "model", + onSelect: () => dialog.show(() => ), + }, + { + id: "mcp.toggle", + title: language.t("command.mcp.toggle"), + description: language.t("command.mcp.toggle.description"), + category: language.t("command.category.mcp"), + keybind: "mod+;", + slash: "mcp", + onSelect: () => dialog.show(() => ), + }, + { + id: "agent.cycle", + title: language.t("command.agent.cycle"), + description: language.t("command.agent.cycle.description"), + category: language.t("command.category.agent"), + keybind: "mod+.", + slash: "agent", + onSelect: () => local.agent.move(1), + }, + { + id: "agent.cycle.reverse", + title: language.t("command.agent.cycle.reverse"), + description: language.t("command.agent.cycle.reverse.description"), + category: language.t("command.category.agent"), + keybind: "shift+mod+.", + onSelect: () => local.agent.move(-1), + }, + { + id: "model.variant.cycle", + title: language.t("command.model.variant.cycle"), + description: language.t("command.model.variant.cycle.description"), + category: language.t("command.category.model"), + keybind: "shift+mod+d", + onSelect: () => { + local.model.variant.cycle() + }, + }, + { + id: "permissions.autoaccept", + title: + params.id && permission.isAutoAccepting(params.id, sdk.directory) + ? language.t("command.permissions.autoaccept.disable") + : language.t("command.permissions.autoaccept.enable"), + category: language.t("command.category.permissions"), + keybind: "mod+shift+a", + disabled: !params.id || !permission.permissionsEnabled(), + onSelect: () => { + const sessionID = params.id + if (!sessionID) return + permission.toggleAutoAccept(sessionID, sdk.directory) + const enabled = permission.isAutoAccepting(sessionID, sdk.directory) + showToast({ + title: enabled + ? language.t("toast.permissions.autoaccept.on.title") + : language.t("toast.permissions.autoaccept.off.title"), + description: enabled + ? language.t("toast.permissions.autoaccept.on.description") + : language.t("toast.permissions.autoaccept.off.description"), + }) + }, + }, + { + id: "session.undo", + title: language.t("command.session.undo"), + description: language.t("command.session.undo.description"), + category: language.t("command.category.session"), + slash: "undo", + disabled: !params.id || visibleUserMessages().length === 0, + onSelect: async () => { + const sessionID = params.id + if (!sessionID) return + if (status()?.type !== "idle") { + await sdk.client.session.abort({ sessionID }).catch(() => {}) + } + const revert = info()?.revert?.messageID + // Find the last user message that's not already reverted + const message = userMessages().findLast((x) => !revert || x.id < revert) + if (!message) return + await sdk.client.session.revert({ sessionID, messageID: message.id }) + // Restore the prompt from the reverted message + const parts = sync.data.part[message.id] + if (parts) { + const restored = extractPromptFromParts(parts, { + directory: sdk.directory, + attachmentName: language.t("common.attachment"), + }) + prompt.set(restored) + } + // Navigate to the message before the reverted one (which will be the new last visible message) + const priorMessage = userMessages().findLast((x) => x.id < message.id) + setActiveMessage(priorMessage) + }, + }, + { + id: "session.redo", + title: language.t("command.session.redo"), + description: language.t("command.session.redo.description"), + category: language.t("command.category.session"), + slash: "redo", + disabled: !params.id || !info()?.revert?.messageID, + onSelect: async () => { + const sessionID = params.id + if (!sessionID) return + const revertMessageID = info()?.revert?.messageID + if (!revertMessageID) return + const nextMessage = userMessages().find((x) => x.id > revertMessageID) + if (!nextMessage) { + // Full unrevert - restore all messages and navigate to last + await sdk.client.session.unrevert({ sessionID }) + prompt.reset() + // Navigate to the last message (the one that was at the revert point) + const lastMsg = userMessages().findLast((x) => x.id >= revertMessageID) + setActiveMessage(lastMsg) + return + } + // Partial redo - move forward to next message + await sdk.client.session.revert({ sessionID, messageID: nextMessage.id }) + // Navigate to the message before the new revert point + const priorMsg = userMessages().findLast((x) => x.id < nextMessage.id) + setActiveMessage(priorMsg) + }, + }, + { + id: "session.compact", + title: language.t("command.session.compact"), + description: language.t("command.session.compact.description"), + category: language.t("command.category.session"), + slash: "compact", + disabled: !params.id || visibleUserMessages().length === 0, + onSelect: async () => { + const sessionID = params.id + if (!sessionID) return + const model = local.model.current() + if (!model) { + showToast({ + title: language.t("toast.model.none.title"), + description: language.t("toast.model.none.description"), + }) + return + } + await sdk.client.session.summarize({ + sessionID, + modelID: model.id, + providerID: model.provider.id, + }) + }, + }, + { + id: "session.fork", + title: language.t("command.session.fork"), + description: language.t("command.session.fork.description"), + category: language.t("command.category.session"), + slash: "fork", + disabled: !params.id || visibleUserMessages().length === 0, + onSelect: () => dialog.show(() => ), + }, + ...(sync.data.config.share !== "disabled" + ? [ + { + id: "session.share", + title: language.t("command.session.share"), + description: language.t("command.session.share.description"), + category: language.t("command.category.session"), + slash: "share", + disabled: !params.id || !!info()?.share?.url, + onSelect: async () => { + if (!params.id) return + await sdk.client.session + .share({ sessionID: params.id }) + .then((res) => { + navigator.clipboard.writeText(res.data!.share!.url).catch(() => + showToast({ + title: language.t("toast.session.share.copyFailed.title"), + variant: "error", + }), + ) + }) + .then(() => + showToast({ + title: language.t("toast.session.share.success.title"), + description: language.t("toast.session.share.success.description"), + variant: "success", + }), + ) + .catch(() => + showToast({ + title: language.t("toast.session.share.failed.title"), + description: language.t("toast.session.share.failed.description"), + variant: "error", + }), + ) + }, + }, + { + id: "session.unshare", + title: language.t("command.session.unshare"), + description: language.t("command.session.unshare.description"), + category: language.t("command.category.session"), + slash: "unshare", + disabled: !params.id || !info()?.share?.url, + onSelect: async () => { + if (!params.id) return + await sdk.client.session + .unshare({ sessionID: params.id }) + .then(() => + showToast({ + title: language.t("toast.session.unshare.success.title"), + description: language.t("toast.session.unshare.success.description"), + variant: "success", + }), + ) + .catch(() => + showToast({ + title: language.t("toast.session.unshare.failed.title"), + description: language.t("toast.session.unshare.failed.description"), + variant: "error", + }), + ) + }, + }, + ] + : []), + ]) + + const handleKeyDown = (event: KeyboardEvent) => { + const activeElement = document.activeElement as HTMLElement | undefined + if (activeElement) { + const isProtected = activeElement.closest("[data-prevent-autofocus]") + const isInput = /^(INPUT|TEXTAREA|SELECT|BUTTON)$/.test(activeElement.tagName) || activeElement.isContentEditable + if (isProtected || isInput) return + } + if (dialog.active) return + + if (activeElement === inputRef) { + if (event.key === "Escape") inputRef?.blur() + return + } + + // Don't autofocus chat if terminal panel is open + if (view().terminal.opened()) return + + // Only treat explicit scroll keys as potential "user scroll" gestures. + if (event.key === "PageUp" || event.key === "PageDown" || event.key === "Home" || event.key === "End") { + markScrollGesture() + return + } + + if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) { + inputRef?.focus() + } + } + + const handleDragStart = (event: unknown) => { + const id = getDraggableId(event) + if (!id) return + setStore("activeDraggable", id) + } + + const handleDragOver = (event: DragEvent) => { + const { draggable, droppable } = event + if (draggable && droppable) { + const currentTabs = tabs().all() + const fromIndex = currentTabs?.indexOf(draggable.id.toString()) + const toIndex = currentTabs?.indexOf(droppable.id.toString()) + if (fromIndex !== toIndex && toIndex !== undefined) { + tabs().move(draggable.id.toString(), toIndex) + } + } + } + + const handleDragEnd = () => { + setStore("activeDraggable", undefined) + } + + const handleTerminalDragStart = (event: unknown) => { + const id = getDraggableId(event) + if (!id) return + setStore("activeTerminalDraggable", id) + } + + const handleTerminalDragOver = (event: DragEvent) => { + const { draggable, droppable } = event + if (draggable && droppable) { + const terminals = terminal.all() + const fromIndex = terminals.findIndex((t: LocalPTY) => t.id === draggable.id.toString()) + const toIndex = terminals.findIndex((t: LocalPTY) => t.id === droppable.id.toString()) + if (fromIndex !== -1 && toIndex !== -1 && fromIndex !== toIndex) { + terminal.move(draggable.id.toString(), toIndex) + } + } + } + + const handleTerminalDragEnd = () => { + setStore("activeTerminalDraggable", undefined) + const activeId = terminal.active() + if (!activeId) return + setTimeout(() => { + const wrapper = document.getElementById(`terminal-wrapper-${activeId}`) + const element = wrapper?.querySelector('[data-component="terminal"]') as HTMLElement + if (!element) return + + // Find and focus the ghostty textarea (the actual input element) + const textarea = element.querySelector("textarea") as HTMLTextAreaElement + if (textarea) { + textarea.focus() + return + } + // Fallback: focus container and dispatch pointer event + element.focus() + element.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true })) + }, 0) + } + + const contextOpen = createMemo(() => tabs().active() === "context" || tabs().all().includes("context")) + const openedTabs = createMemo(() => + tabs() + .all() + .filter((tab) => tab !== "context"), + ) + + const mobileReview = createMemo(() => !isDesktop() && view().reviewPanel.opened() && store.mobileTab === "review") + + const showTabs = createMemo(() => view().reviewPanel.opened()) + + const activeTab = createMemo(() => { + const active = tabs().active() + if (active) return active + if (hasReview()) return "review" + + const first = openedTabs()[0] + if (first) return first + if (contextOpen()) return "context" + return "review" + }) + + createEffect(() => { + if (!layout.ready()) return + if (tabs().active()) return + if (!hasReview() && openedTabs().length === 0 && !contextOpen()) return + tabs().setActive(activeTab()) + }) + + createEffect(() => { + const id = params.id + if (!id) return + if (!hasReview()) return + + const wants = isDesktop() ? view().reviewPanel.opened() && activeTab() === "review" : store.mobileTab === "review" + if (!wants) return + if (diffsReady()) return + + sync.session.diff(id) + }) + + const autoScroll = createAutoScroll({ + working: () => true, + overflowAnchor: "dynamic", + }) + + const resumeScroll = () => { + setStore("messageId", undefined) + autoScroll.forceScrollToBottom() + } + + // When the user returns to the bottom, treat the active message as "latest". + createEffect( + on( + autoScroll.userScrolled, + (scrolled) => { + if (scrolled) return + setStore("messageId", undefined) + }, + { defer: true }, + ), + ) + + let scrollSpyFrame: number | undefined + let scrollSpyTarget: HTMLDivElement | undefined + + const anchor = (id: string) => `message-${id}` + + const setScrollRef = (el: HTMLDivElement | undefined) => { + scroller = el + autoScroll.scrollRef(el) + } + + const turnInit = 20 + const turnBatch = 20 + let turnHandle: number | undefined + let turnIdle = false + + function cancelTurnBackfill() { + const handle = turnHandle + if (handle === undefined) return + turnHandle = undefined + + if (turnIdle && window.cancelIdleCallback) { + window.cancelIdleCallback(handle) + return + } + + clearTimeout(handle) + } + + function scheduleTurnBackfill() { + if (turnHandle !== undefined) return + if (store.turnStart <= 0) return + + if (window.requestIdleCallback) { + turnIdle = true + turnHandle = window.requestIdleCallback(() => { + turnHandle = undefined + backfillTurns() + }) + return + } + + turnIdle = false + turnHandle = window.setTimeout(() => { + turnHandle = undefined + backfillTurns() + }, 0) + } + + function backfillTurns() { + const start = store.turnStart + if (start <= 0) return + + const next = start - turnBatch + const nextStart = next > 0 ? next : 0 + + const el = scroller + if (!el) { + setStore("turnStart", nextStart) + scheduleTurnBackfill() + return + } + + const beforeTop = el.scrollTop + const beforeHeight = el.scrollHeight + + setStore("turnStart", nextStart) + + requestAnimationFrame(() => { + const delta = el.scrollHeight - beforeHeight + if (delta) el.scrollTop = beforeTop + delta + }) + + scheduleTurnBackfill() + } + + createEffect( + on( + () => [params.id, messagesReady()] as const, + ([id, ready]) => { + cancelTurnBackfill() + setStore("turnStart", 0) + if (!id || !ready) return + + const len = visibleUserMessages().length + const start = len > turnInit ? len - turnInit : 0 + setStore("turnStart", start) + scheduleTurnBackfill() + }, + { defer: true }, + ), + ) + + createResizeObserver( + () => promptDock, + ({ height }) => { + const next = Math.ceil(height) + + if (next === store.promptHeight) return + + const el = scroller + const stick = el ? el.scrollHeight - el.clientHeight - el.scrollTop < 10 : false + + setStore("promptHeight", next) + + if (stick && el) { + requestAnimationFrame(() => { + el.scrollTo({ top: el.scrollHeight, behavior: "auto" }) + }) + } + }, + ) + + const updateHash = (id: string) => { + window.history.replaceState(null, "", `#${anchor(id)}`) + } + + createEffect(() => { + const sessionID = params.id + if (!sessionID) return + const raw = sessionStorage.getItem("opencode.pendingMessage") + if (!raw) return + const parts = raw.split("|") + const pendingSessionID = parts[0] + const messageID = parts[1] + if (!pendingSessionID || !messageID) return + if (pendingSessionID !== sessionID) return + + sessionStorage.removeItem("opencode.pendingMessage") + setPendingMessage(messageID) + }) + + const scrollToElement = (el: HTMLElement, behavior: ScrollBehavior) => { + const root = scroller + if (!root) return false + + const a = el.getBoundingClientRect() + const b = root.getBoundingClientRect() + const offset = (info()?.title ? 40 : 0) + 12 + const top = a.top - b.top + root.scrollTop - offset + root.scrollTo({ top: top > 0 ? top : 0, behavior }) + return true + } + + const scrollToMessage = (message: UserMessage, behavior: ScrollBehavior = "smooth") => { + // Navigating to a specific message should always pause auto-follow. + autoScroll.pause() + setActiveMessage(message) + updateHash(message.id) + + const msgs = visibleUserMessages() + const index = msgs.findIndex((m) => m.id === message.id) + if (index !== -1 && index < store.turnStart) { + setStore("turnStart", index) + scheduleTurnBackfill() + } + + const id = anchor(message.id) + const attempt = (tries: number) => { + const el = document.getElementById(id) + if (el && scrollToElement(el, behavior)) return + if (tries >= 8) return + requestAnimationFrame(() => attempt(tries + 1)) + } + attempt(0) + } + + const applyHash = (behavior: ScrollBehavior) => { + const hash = window.location.hash.slice(1) + if (!hash) { + setPendingHash(undefined) + autoScroll.forceScrollToBottom() + return + } + + const match = hash.match(/^message-(.+)$/) + if (match) { + const msg = visibleUserMessages().find((m) => m.id === match[1]) + if (msg) { + setPendingHash(undefined) + scrollToMessage(msg, behavior) + return + } + + // If we have a message hash but the message isn't loaded/rendered yet, + // don't fall back to "bottom". We'll retry once messages arrive. + setPendingHash(match[1]) + return + } + + const target = document.getElementById(hash) + if (target) { + setPendingHash(undefined) + scrollToElement(target, behavior) + return + } + + setPendingHash(undefined) + autoScroll.forceScrollToBottom() + } + + const getActiveMessageId = (container: HTMLDivElement) => { + const cutoff = container.scrollTop + 100 + const nodes = container.querySelectorAll("[data-message-id]") + let id: string | undefined + + for (const node of nodes) { + const next = node.dataset.messageId + if (!next) continue + if (node.offsetTop > cutoff) break + id = next + } + + return id + } + + const scheduleScrollSpy = (container: HTMLDivElement) => { + scrollSpyTarget = container + if (scrollSpyFrame !== undefined) return + + scrollSpyFrame = requestAnimationFrame(() => { + scrollSpyFrame = undefined + + const target = scrollSpyTarget + scrollSpyTarget = undefined + if (!target) return + + const id = getActiveMessageId(target) + if (!id) return + if (id === store.messageId) return + + setStore("messageId", id) + }) + } + + createEffect(() => { + const sessionID = params.id + const ready = messagesReady() + if (!sessionID || !ready) return + + requestAnimationFrame(() => { + applyHash("auto") + }) + }) + + // Retry message navigation once the target message is actually loaded. + createEffect(() => { + const sessionID = params.id + const ready = messagesReady() + if (!sessionID || !ready) return + + // dependencies + visibleUserMessages().length + store.turnStart + + const targetId = pendingMessage() ?? pendingHash() + if (!targetId) return + if (store.messageId === targetId) return + + const msg = visibleUserMessages().find((m) => m.id === targetId) + if (!msg) return + if (pendingMessage() === targetId) setPendingMessage(undefined) + if (pendingHash() === targetId) setPendingHash(undefined) + requestAnimationFrame(() => scrollToMessage(msg, "auto")) + }) + + createEffect(() => { + const sessionID = params.id + const ready = messagesReady() + if (!sessionID || !ready) return + + const handler = () => requestAnimationFrame(() => applyHash("auto")) + window.addEventListener("hashchange", handler) + onCleanup(() => window.removeEventListener("hashchange", handler)) + }) + + createEffect(() => { + document.addEventListener("keydown", handleKeyDown) + }) + + const previewPrompt = () => + prompt + .current() + .map((part) => { + if (part.type === "file") return `[file:${part.path}]` + if (part.type === "agent") return `@${part.name}` + if (part.type === "image") return `[image:${part.filename}]` + return part.content + }) + .join("") + .trim() + + createEffect(() => { + if (!prompt.ready()) return + handoff.prompt = previewPrompt() + }) + + createEffect(() => { + if (!terminal.ready()) return + language.locale() + + const label = (pty: LocalPTY) => { + const title = pty.title + const number = pty.titleNumber + const match = title.match(/^Terminal (\d+)$/) + const parsed = match ? Number(match[1]) : undefined + const isDefaultTitle = Number.isFinite(number) && number > 0 && Number.isFinite(parsed) && parsed === number + + if (title && !isDefaultTitle) return title + if (Number.isFinite(number) && number > 0) return language.t("terminal.title.numbered", { number }) + if (title) return title + return language.t("terminal.title") + } + + handoff.terminals = terminal.all().map(label) + }) + + createEffect(() => { + if (!file.ready()) return + handoff.files = Object.fromEntries( + tabs() + .all() + .flatMap((tab) => { + const path = file.pathFromTab(tab) + if (!path) return [] + return [[path, file.selectedLines(path) ?? null] as const] + }), + ) + }) + + onCleanup(() => { + cancelTurnBackfill() + document.removeEventListener("keydown", handleKeyDown) + if (scrollSpyFrame !== undefined) cancelAnimationFrame(scrollSpyFrame) + }) + + return ( +
+ +
+ {/* Mobile tab bar - only shown on mobile when user opened review */} + + + + setStore("mobileTab", "session")} + > + {language.t("session.tab.session")} + + setStore("mobileTab", "review")} + > + + + {language.t("session.review.filesChanged", { count: reviewCount() })} + + {language.t("session.tab.review")} + + + + + + + {/* Session panel */} +
+
+ + + + + + + + {language.t("session.review.loadingChanges")} +
+ } + > + { + const value = file.tab(path) + tabs().open(value) + file.load(path) + }} + classes={{ + root: "pb-[calc(var(--prompt-height,8rem)+32px)]", + header: "px-4", + container: "px-4", + }} + /> + + + +
+ +
+ {language.t("session.review.empty")} +
+
+
+ +
+ } + > +
+
+ +
+
markScrollGesture(e.target)} + onTouchMove={(e) => markScrollGesture(e.target)} + onPointerDown={(e) => { + if (e.target !== e.currentTarget) return + markScrollGesture(e.target) + }} + onScroll={(e) => { + if (!hasScrollGesture()) return + markScrollGesture(e.target) + autoScroll.handleScroll() + if (isDesktop() && autoScroll.userScrolled()) scheduleScrollSpy(e.currentTarget) + }} + class="relative min-w-0 w-full h-full overflow-y-auto session-scroller" + style={{ "--session-title-height": info()?.title ? "40px" : "0px" }} + > + +
+
+

{info()?.title}

+
+
+
+ +
+ 0}> +
+ +
+
+ +
+ +
+
+ + {(message) => { + if (import.meta.env.DEV) { + onMount(() => { + const id = params.id + if (!id) return + navMark({ dir: params.dir, to: id, name: "session:first-turn-mounted" }) + }) + } + + return ( +
+ + setStore("expanded", message.id, (open: boolean | undefined) => !open) + } + classes={{ + root: "min-w-0 w-full relative", + content: "flex flex-col justify-between !overflow-visible", + container: "w-full px-4 md:px-6", + }} + /> +
+ ) + }} +
+
+
+
+ + + + + { + if (value === "create") { + setStore("newSessionWorktree", value) + return + } + + setStore("newSessionWorktree", "main") + + const target = value === "main" ? sync.project?.worktree : value + if (!target) return + if (target === sync.data.path.directory) return + layout.projects.open(target) + navigate(`/${base64Encode(target)}/session`) + }} + /> + + +
+ + {/* Prompt input */} +
(promptDock = el)} + class="absolute inset-x-0 bottom-0 pt-12 pb-4 md:pb-6 flex flex-col justify-center items-center z-50 px-4 md:px-0 bg-gradient-to-t from-background-stronger via-background-stronger to-transparent pointer-events-none" + > +
+ + {handoff.prompt || language.t("prompt.loading")} +
+ } + > + { + inputRef = el + }} + newSessionWorktree={newSessionWorktree()} + onNewSessionWorktreeReset={() => setStore("newSessionWorktree", "main")} + onSubmit={resumeScroll} + /> + +
+
+ + + + +
+ + {/* Desktop tabs panel (Review + Context + Files) - hidden on mobile */} + +
+ + + + + + +
+ +
+
+
+
+ + {(tab) => { + let scroll: HTMLDivElement | undefined + let scrollFrame: number | undefined + let pending: { x: number; y: number } | undefined + + const path = createMemo(() => file.pathFromTab(tab)) + const state = createMemo(() => { + const p = path() + if (!p) return + return file.get(p) + }) + const contents = createMemo(() => state()?.content?.content ?? "") + const cacheKey = createMemo(() => checksum(contents())) + const isImage = createMemo(() => { + const c = state()?.content + return ( + c?.encoding === "base64" && c?.mimeType?.startsWith("image/") && c?.mimeType !== "image/svg+xml" + ) + }) + const isSvg = createMemo(() => { + const c = state()?.content + return c?.mimeType === "image/svg+xml" + }) + const svgContent = createMemo(() => { + if (!isSvg()) return + const c = state()?.content + if (!c) return + if (c.encoding === "base64") return base64Decode(c.content) + return c.content + }) + const svgPreviewUrl = createMemo(() => { + if (!isSvg()) return + const c = state()?.content + if (!c) return + if (c.encoding === "base64") return `data:image/svg+xml;base64,${c.content}` + return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(c.content)}` + }) + const imageDataUrl = createMemo(() => { + if (!isImage()) return + const c = state()?.content + return `data:${c?.mimeType};base64,${c?.content}` + }) + const selectedLines = createMemo(() => { + const p = path() + if (!p) return null + if (file.ready()) return file.selectedLines(p) ?? null + return handoff.files[p] ?? null + }) + const selection = createMemo(() => { + const range = selectedLines() + if (!range) return + return selectionFromLines(range) + }) + const selectionLabel = createMemo(() => { + const sel = selection() + if (!sel) return + if (sel.startLine === sel.endLine) return `L${sel.startLine}` + return `L${sel.startLine}-${sel.endLine}` + }) + + const restoreScroll = (retries = 0) => { + const el = scroll + if (!el) return + + const s = view()?.scroll(tab) + if (!s) return + + // Wait for content to be scrollable - content may not have rendered yet + if (el.scrollHeight <= el.clientHeight && retries < 10) { + requestAnimationFrame(() => restoreScroll(retries + 1)) + return + } + + if (el.scrollTop !== s.y) el.scrollTop = s.y + if (el.scrollLeft !== s.x) el.scrollLeft = s.x + } + + const handleScroll = (event: Event & { currentTarget: HTMLDivElement }) => { + pending = { + x: event.currentTarget.scrollLeft, + y: event.currentTarget.scrollTop, + } + if (scrollFrame !== undefined) return + + scrollFrame = requestAnimationFrame(() => { + scrollFrame = undefined + + const next = pending + pending = undefined + if (!next) return + + view().setScroll(tab, next) + }) + } + + createEffect( + on( + () => state()?.loaded, + (loaded) => { + if (!loaded) return + requestAnimationFrame(restoreScroll) + }, + { defer: true }, + ), + ) + + createEffect( + on( + () => file.ready(), + (ready) => { + if (!ready) return + requestAnimationFrame(restoreScroll) + }, + { defer: true }, + ), + ) + + createEffect( + on( + () => tabs().active() === tab, + (active) => { + if (!active) return + if (!state()?.loaded) return + requestAnimationFrame(restoreScroll) + }, + ), + ) + + onCleanup(() => { + if (scrollFrame === undefined) return + cancelAnimationFrame(scrollFrame) + }) + + return ( + { + scroll = el + restoreScroll() + }} + onScroll={handleScroll} + > + + + {(sel) => ( + + )} + + + +
+ {path()} +
+
+ +
+ { + const p = path() + if (!p) return + file.setSelectedLines(p, range) + }} + overflow="scroll" + class="select-text" + /> + +
+ {path()} +
+
+
+
+ + { + const p = path() + if (!p) return + file.setSelectedLines(p, range) + }} + overflow="scroll" + class="select-text pb-40" + /> + + +
{language.t("common.loading")}...
+
+ + {(err) =>
{err()}
} +
+
+
+
+ ) + }} +
+ + + + {(tab) => { + const path = createMemo(() => file.pathFromTab(tab())) + return ( +
+ {(p) => } +
+ ) + }} +
+
+ + + +
+ + +
+ + +
+ + {(title) => ( +
+ {title} +
+ )} +
+
+
{language.t("common.loading")}...
+
+
+ {language.t("terminal.loading")} +
+
+ } + > + + + +
+ { + // Only switch tabs if not in the middle of starting edit mode + terminal.open(id) + }} + class="!h-auto !flex-none" + > + + t.id)}> + + {(pty) => ( + { + view().terminal.close() + setAutoCreated(false) + }} + /> + )} + + +
+ + + +
+
+
+
+ + {(pty) => { + const [dismissed, setDismissed] = createSignal(false) + return ( +
+ terminal.update({ ...data, id: pty.id })} + onConnect={() => { + terminal.update({ id: pty.id, error: false }) + setDismissed(false) + }} + onConnectError={() => { + setDismissed(false) + terminal.update({ id: pty.id, error: true }) + }} + /> + +
+ +
+
{language.t("terminal.connectionLost.title")}
+
+ {language.t("terminal.connectionLost.description")} +
+
+ +
+
+
+ ) + }} +
+
+
+ + + {(draggedId) => { + const pty = createMemo(() => terminal.all().find((t: LocalPTY) => t.id === draggedId())) + return ( + + {(t) => ( +
+ {(() => { + const title = t().title + const number = t().titleNumber + const match = title.match(/^Terminal (\d+)$/) + const parsed = match ? Number(match[1]) : undefined + const isDefaultTitle = + Number.isFinite(number) && number > 0 && Number.isFinite(parsed) && parsed === number + + if (title && !isDefaultTitle) return title + if (Number.isFinite(number) && number > 0) + return language.t("terminal.title.numbered", { number }) + if (title) return title + return language.t("terminal.title") + })()} +
+ )} +
+ ) + }} +
+
+
+
+
+
+
+ ) +} diff --git a/packages/app/src/sst-env.d.ts b/packages/app/src/sst-env.d.ts new file mode 100644 index 00000000000..47a8fbec7bf --- /dev/null +++ b/packages/app/src/sst-env.d.ts @@ -0,0 +1,10 @@ +/* This file is auto-generated by SST. Do not edit. */ +/* tslint:disable */ +/* eslint-disable */ +/// +interface ImportMetaEnv { + +} +interface ImportMeta { + readonly env: ImportMetaEnv +} \ No newline at end of file diff --git a/packages/app/src/utils/dom.ts b/packages/app/src/utils/dom.ts new file mode 100644 index 00000000000..4f3724c7c95 --- /dev/null +++ b/packages/app/src/utils/dom.ts @@ -0,0 +1,51 @@ +export function getCharacterOffsetInLine(lineElement: Element, targetNode: Node, offset: number): number { + const r = document.createRange() + r.selectNodeContents(lineElement) + r.setEnd(targetNode, offset) + return r.toString().length +} + +export function getNodeOffsetInLine(lineElement: Element, charIndex: number): { node: Node; offset: number } | null { + const walker = document.createTreeWalker(lineElement, NodeFilter.SHOW_TEXT, null) + let remaining = Math.max(0, charIndex) + let lastText: Node | null = null + let lastLen = 0 + let node: Node | null + while ((node = walker.nextNode())) { + const len = node.textContent?.length || 0 + lastText = node + lastLen = len + if (remaining <= len) return { node, offset: remaining } + remaining -= len + } + if (lastText) return { node: lastText, offset: lastLen } + if (lineElement.firstChild) return { node: lineElement.firstChild, offset: 0 } + return null +} + +export function getSelectionInContainer( + container: HTMLElement, +): { sl: number; sch: number; el: number; ech: number } | null { + const s = window.getSelection() + if (!s || s.rangeCount === 0) return null + const r = s.getRangeAt(0) + const sc = r.startContainer + const ec = r.endContainer + const getLineElement = (n: Node) => + (n.nodeType === Node.TEXT_NODE ? (n.parentElement as Element) : (n as Element))?.closest(".line") + const sle = getLineElement(sc) + const ele = getLineElement(ec) + if (!sle || !ele) return null + if (!container.contains(sle as Node) || !container.contains(ele as Node)) return null + const cc = container.querySelector("code") as HTMLElement | null + if (!cc) return null + const lines = Array.from(cc.querySelectorAll(".line")) + const sli = lines.indexOf(sle as Element) + const eli = lines.indexOf(ele as Element) + if (sli === -1 || eli === -1) return null + const sl = sli + 1 + const el = eli + 1 + const sch = getCharacterOffsetInLine(sle as Element, sc, r.startOffset) + const ech = getCharacterOffsetInLine(ele as Element, ec, r.endOffset) + return { sl, sch, el, ech } +} diff --git a/packages/app/src/utils/id.ts b/packages/app/src/utils/id.ts new file mode 100644 index 00000000000..fa27cf4c5f9 --- /dev/null +++ b/packages/app/src/utils/id.ts @@ -0,0 +1,99 @@ +import z from "zod" + +const prefixes = { + session: "ses", + message: "msg", + permission: "per", + user: "usr", + part: "prt", + pty: "pty", +} as const + +const LENGTH = 26 +let lastTimestamp = 0 +let counter = 0 + +type Prefix = keyof typeof prefixes +export namespace Identifier { + export function schema(prefix: Prefix) { + return z.string().startsWith(prefixes[prefix]) + } + + export function ascending(prefix: Prefix, given?: string) { + return generateID(prefix, false, given) + } + + export function descending(prefix: Prefix, given?: string) { + return generateID(prefix, true, given) + } +} + +function generateID(prefix: Prefix, descending: boolean, given?: string): string { + if (!given) { + return create(prefix, descending) + } + + if (!given.startsWith(prefixes[prefix])) { + throw new Error(`ID ${given} does not start with ${prefixes[prefix]}`) + } + + return given +} + +function create(prefix: Prefix, descending: boolean, timestamp?: number): string { + const currentTimestamp = timestamp ?? Date.now() + + if (currentTimestamp !== lastTimestamp) { + lastTimestamp = currentTimestamp + counter = 0 + } + + counter += 1 + + let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter) + + if (descending) { + now = ~now + } + + const timeBytes = new Uint8Array(6) + for (let i = 0; i < 6; i += 1) { + timeBytes[i] = Number((now >> BigInt(40 - 8 * i)) & BigInt(0xff)) + } + + return prefixes[prefix] + "_" + bytesToHex(timeBytes) + randomBase62(LENGTH - 12) +} + +function bytesToHex(bytes: Uint8Array): string { + let hex = "" + for (let i = 0; i < bytes.length; i += 1) { + hex += bytes[i].toString(16).padStart(2, "0") + } + return hex +} + +function randomBase62(length: number): string { + const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + const bytes = getRandomBytes(length) + let result = "" + for (let i = 0; i < length; i += 1) { + result += chars[bytes[i] % 62] + } + return result +} + +function getRandomBytes(length: number): Uint8Array { + const bytes = new Uint8Array(length) + const cryptoObj = typeof globalThis !== "undefined" ? globalThis.crypto : undefined + + if (cryptoObj && typeof cryptoObj.getRandomValues === "function") { + cryptoObj.getRandomValues(bytes) + return bytes + } + + for (let i = 0; i < length; i += 1) { + bytes[i] = Math.floor(Math.random() * 256) + } + + return bytes +} diff --git a/packages/app/src/utils/index.ts b/packages/app/src/utils/index.ts new file mode 100644 index 00000000000..d87053269df --- /dev/null +++ b/packages/app/src/utils/index.ts @@ -0,0 +1 @@ +export * from "./dom" diff --git a/packages/app/src/utils/perf.ts b/packages/app/src/utils/perf.ts new file mode 100644 index 00000000000..0ecbc33ffc1 --- /dev/null +++ b/packages/app/src/utils/perf.ts @@ -0,0 +1,135 @@ +type Nav = { + id: string + dir?: string + from?: string + to: string + trigger?: string + start: number + marks: Record + logged: boolean + timer?: ReturnType +} + +const dev = import.meta.env.DEV + +const key = (dir: string | undefined, to: string) => `${dir ?? ""}:${to}` + +const now = () => performance.now() + +const uid = () => crypto.randomUUID?.() ?? Math.random().toString(16).slice(2) + +const navs = new Map() +const pending = new Map() +const active = new Map() + +const required = [ + "session:params", + "session:data-ready", + "session:first-turn-mounted", + "storage:prompt-ready", + "storage:terminal-ready", + "storage:file-view-ready", +] + +function flush(id: string, reason: "complete" | "timeout") { + if (!dev) return + const nav = navs.get(id) + if (!nav) return + if (nav.logged) return + + nav.logged = true + if (nav.timer) clearTimeout(nav.timer) + + const baseName = nav.marks["navigate:start"] !== undefined ? "navigate:start" : "session:params" + const base = nav.marks[baseName] ?? nav.start + + const ms = Object.fromEntries( + Object.entries(nav.marks) + .slice() + .sort(([a], [b]) => a.localeCompare(b)) + .map(([name, t]) => [name, Math.round((t - base) * 100) / 100]), + ) + + console.log( + "perf.session-nav " + + JSON.stringify({ + type: "perf.session-nav.v0", + id: nav.id, + dir: nav.dir, + from: nav.from, + to: nav.to, + trigger: nav.trigger, + base: baseName, + reason, + ms, + }), + ) + + navs.delete(id) +} + +function maybeFlush(id: string) { + if (!dev) return + const nav = navs.get(id) + if (!nav) return + if (nav.logged) return + if (!required.every((name) => nav.marks[name] !== undefined)) return + flush(id, "complete") +} + +function ensure(id: string, data: Omit) { + const existing = navs.get(id) + if (existing) return existing + + const nav: Nav = { + ...data, + marks: {}, + logged: false, + } + nav.timer = setTimeout(() => flush(id, "timeout"), 5000) + navs.set(id, nav) + return nav +} + +export function navStart(input: { dir?: string; from?: string; to: string; trigger?: string }) { + if (!dev) return + + const id = uid() + const start = now() + const nav = ensure(id, { ...input, id, start }) + nav.marks["navigate:start"] = start + + pending.set(key(input.dir, input.to), id) + return id +} + +export function navParams(input: { dir?: string; from?: string; to: string }) { + if (!dev) return + + const k = key(input.dir, input.to) + const pendingId = pending.get(k) + if (pendingId) pending.delete(k) + const id = pendingId ?? uid() + + const start = now() + const nav = ensure(id, { ...input, id, start, trigger: pendingId ? "key" : "route" }) + nav.marks["session:params"] = start + + active.set(k, id) + maybeFlush(id) + return id +} + +export function navMark(input: { dir?: string; to: string; name: string }) { + if (!dev) return + + const id = active.get(key(input.dir, input.to)) + if (!id) return + + const nav = navs.get(id) + if (!nav) return + if (nav.marks[input.name] !== undefined) return + + nav.marks[input.name] = now() + maybeFlush(id) +} diff --git a/packages/app/src/utils/persist.ts b/packages/app/src/utils/persist.ts new file mode 100644 index 00000000000..70884977c75 --- /dev/null +++ b/packages/app/src/utils/persist.ts @@ -0,0 +1,377 @@ +import { usePlatform } from "@/context/platform" +import { makePersisted, type AsyncStorage, type SyncStorage } from "@solid-primitives/storage" +import { checksum } from "@opencode-ai/util/encode" +import { createResource, type Accessor } from "solid-js" +import type { SetStoreFunction, Store } from "solid-js/store" + +type InitType = Promise | string | null +type PersistedWithReady = [Store, SetStoreFunction, InitType, Accessor] + +type PersistTarget = { + storage?: string + key: string + legacy?: string[] + migrate?: (value: unknown) => unknown +} + +const LEGACY_STORAGE = "default.dat" +const GLOBAL_STORAGE = "opencode.global.dat" +const LOCAL_PREFIX = "opencode." +const fallback = { disabled: false } +const cache = new Map() + +function quota(error: unknown) { + if (error instanceof DOMException) { + if (error.name === "QuotaExceededError") return true + if (error.name === "NS_ERROR_DOM_QUOTA_REACHED") return true + if (error.name === "QUOTA_EXCEEDED_ERR") return true + if (error.code === 22 || error.code === 1014) return true + return false + } + + if (!error || typeof error !== "object") return false + const name = (error as { name?: string }).name + if (name === "QuotaExceededError" || name === "NS_ERROR_DOM_QUOTA_REACHED") return true + if (name && /quota/i.test(name)) return true + + const code = (error as { code?: number }).code + if (code === 22 || code === 1014) return true + + const message = (error as { message?: string }).message + if (typeof message !== "string") return false + if (/quota/i.test(message)) return true + return false +} + +type Evict = { key: string; size: number } + +function evict(storage: Storage, keep: string, value: string) { + const total = storage.length + const indexes = Array.from({ length: total }, (_, index) => index) + const items: Evict[] = [] + + for (const index of indexes) { + const name = storage.key(index) + if (!name) continue + if (!name.startsWith(LOCAL_PREFIX)) continue + if (name === keep) continue + const stored = storage.getItem(name) + items.push({ key: name, size: stored?.length ?? 0 }) + } + + items.sort((a, b) => b.size - a.size) + + for (const item of items) { + storage.removeItem(item.key) + + try { + storage.setItem(keep, value) + return true + } catch (error) { + if (!quota(error)) throw error + } + } + + return false +} + +function write(storage: Storage, key: string, value: string) { + try { + storage.setItem(key, value) + return true + } catch (error) { + if (!quota(error)) throw error + } + + try { + storage.removeItem(key) + storage.setItem(key, value) + return true + } catch (error) { + if (!quota(error)) throw error + } + + return evict(storage, key, value) +} + +function snapshot(value: unknown) { + return JSON.parse(JSON.stringify(value)) as unknown +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value) +} + +function merge(defaults: unknown, value: unknown): unknown { + if (value === undefined) return defaults + if (value === null) return value + + if (Array.isArray(defaults)) { + if (Array.isArray(value)) return value + return defaults + } + + if (isRecord(defaults)) { + if (!isRecord(value)) return defaults + + const result: Record = { ...defaults } + for (const key of Object.keys(value)) { + if (key in defaults) { + result[key] = merge((defaults as Record)[key], (value as Record)[key]) + } else { + result[key] = (value as Record)[key] + } + } + return result + } + + return value +} + +function parse(value: string) { + try { + return JSON.parse(value) as unknown + } catch { + return undefined + } +} + +function workspaceStorage(dir: string) { + const head = dir.slice(0, 12) || "workspace" + const sum = checksum(dir) ?? "0" + return `opencode.workspace.${head}.${sum}.dat` +} + +function localStorageWithPrefix(prefix: string): SyncStorage { + const base = `${prefix}:` + const item = (key: string) => base + key + return { + getItem: (key) => { + const name = item(key) + const cached = cache.get(name) + if (fallback.disabled && cached !== undefined) return cached + + const stored = localStorage.getItem(name) + if (stored === null) return cached ?? null + cache.set(name, stored) + return stored + }, + setItem: (key, value) => { + const name = item(key) + cache.set(name, value) + if (fallback.disabled) return + try { + if (write(localStorage, name, value)) return + } catch { + fallback.disabled = true + return + } + fallback.disabled = true + }, + removeItem: (key) => { + const name = item(key) + cache.delete(name) + if (fallback.disabled) return + localStorage.removeItem(name) + }, + } +} + +function localStorageDirect(): SyncStorage { + return { + getItem: (key) => { + const cached = cache.get(key) + if (fallback.disabled && cached !== undefined) return cached + + const stored = localStorage.getItem(key) + if (stored === null) return cached ?? null + cache.set(key, stored) + return stored + }, + setItem: (key, value) => { + cache.set(key, value) + if (fallback.disabled) return + try { + if (write(localStorage, key, value)) return + } catch { + fallback.disabled = true + return + } + fallback.disabled = true + }, + removeItem: (key) => { + cache.delete(key) + if (fallback.disabled) return + localStorage.removeItem(key) + }, + } +} + +export const Persist = { + global(key: string, legacy?: string[]): PersistTarget { + return { storage: GLOBAL_STORAGE, key, legacy } + }, + workspace(dir: string, key: string, legacy?: string[]): PersistTarget { + return { storage: workspaceStorage(dir), key: `workspace:${key}`, legacy } + }, + session(dir: string, session: string, key: string, legacy?: string[]): PersistTarget { + return { storage: workspaceStorage(dir), key: `session:${session}:${key}`, legacy } + }, + scoped(dir: string, session: string | undefined, key: string, legacy?: string[]): PersistTarget { + if (session) return Persist.session(dir, session, key, legacy) + return Persist.workspace(dir, key, legacy) + }, +} + +export function removePersisted(target: { storage?: string; key: string }) { + const platform = usePlatform() + const isDesktop = platform.platform === "desktop" && !!platform.storage + + if (isDesktop) { + return platform.storage?.(target.storage)?.removeItem(target.key) + } + + if (!target.storage) { + localStorageDirect().removeItem(target.key) + return + } + + localStorageWithPrefix(target.storage).removeItem(target.key) +} + +export function persisted( + target: string | PersistTarget, + store: [Store, SetStoreFunction], +): PersistedWithReady { + const platform = usePlatform() + const config: PersistTarget = typeof target === "string" ? { key: target } : target + + const defaults = snapshot(store[0]) + const legacy = config.legacy ?? [] + + const isDesktop = platform.platform === "desktop" && !!platform.storage + + const currentStorage = (() => { + if (isDesktop) return platform.storage?.(config.storage) + if (!config.storage) return localStorageDirect() + return localStorageWithPrefix(config.storage) + })() + + const legacyStorage = (() => { + if (!isDesktop) return localStorageDirect() + if (!config.storage) return platform.storage?.() + return platform.storage?.(LEGACY_STORAGE) + })() + + const storage = (() => { + if (!isDesktop) { + const current = currentStorage as SyncStorage + const legacyStore = legacyStorage as SyncStorage + + const api: SyncStorage = { + getItem: (key) => { + const raw = current.getItem(key) + if (raw !== null) { + const parsed = parse(raw) + if (parsed === undefined) return raw + + const migrated = config.migrate ? config.migrate(parsed) : parsed + const merged = merge(defaults, migrated) + const next = JSON.stringify(merged) + if (raw !== next) current.setItem(key, next) + return next + } + + for (const legacyKey of legacy) { + const legacyRaw = legacyStore.getItem(legacyKey) + if (legacyRaw === null) continue + + current.setItem(key, legacyRaw) + legacyStore.removeItem(legacyKey) + + const parsed = parse(legacyRaw) + if (parsed === undefined) return legacyRaw + + const migrated = config.migrate ? config.migrate(parsed) : parsed + const merged = merge(defaults, migrated) + const next = JSON.stringify(merged) + if (legacyRaw !== next) current.setItem(key, next) + return next + } + + return null + }, + setItem: (key, value) => { + current.setItem(key, value) + }, + removeItem: (key) => { + current.removeItem(key) + }, + } + + return api + } + + const current = currentStorage as AsyncStorage + const legacyStore = legacyStorage as AsyncStorage | undefined + + const api: AsyncStorage = { + getItem: async (key) => { + const raw = await current.getItem(key) + if (raw !== null) { + const parsed = parse(raw) + if (parsed === undefined) return raw + + const migrated = config.migrate ? config.migrate(parsed) : parsed + const merged = merge(defaults, migrated) + const next = JSON.stringify(merged) + if (raw !== next) await current.setItem(key, next) + return next + } + + if (!legacyStore) return null + + for (const legacyKey of legacy) { + const legacyRaw = await legacyStore.getItem(legacyKey) + if (legacyRaw === null) continue + + await current.setItem(key, legacyRaw) + await legacyStore.removeItem(legacyKey) + + const parsed = parse(legacyRaw) + if (parsed === undefined) return legacyRaw + + const migrated = config.migrate ? config.migrate(parsed) : parsed + const merged = merge(defaults, migrated) + const next = JSON.stringify(merged) + if (legacyRaw !== next) await current.setItem(key, next) + return next + } + + return null + }, + setItem: async (key, value) => { + await current.setItem(key, value) + }, + removeItem: async (key) => { + await current.removeItem(key) + }, + } + + return api + })() + + const [state, setState, init] = makePersisted(store, { name: config.key, storage }) + + const isAsync = init instanceof Promise + const [ready] = createResource( + () => init, + async (initValue) => { + if (initValue instanceof Promise) await initValue + return true + }, + { initialValue: !isAsync }, + ) + + return [state, setState, init, () => ready() === true] +} diff --git a/packages/app/src/utils/prompt.ts b/packages/app/src/utils/prompt.ts new file mode 100644 index 00000000000..35aec0071aa --- /dev/null +++ b/packages/app/src/utils/prompt.ts @@ -0,0 +1,203 @@ +import type { AgentPart as MessageAgentPart, FilePart, Part, TextPart } from "@opencode-ai/sdk/v2" +import type { AgentPart, FileAttachmentPart, ImageAttachmentPart, Prompt } from "@/context/prompt" + +type Inline = + | { + type: "file" + start: number + end: number + value: string + path: string + selection?: { + startLine: number + endLine: number + startChar: number + endChar: number + } + } + | { + type: "agent" + start: number + end: number + value: string + name: string + } + +function selectionFromFileUrl(url: string): Extract["selection"] { + const queryIndex = url.indexOf("?") + if (queryIndex === -1) return undefined + const params = new URLSearchParams(url.slice(queryIndex + 1)) + const startLine = Number(params.get("start")) + const endLine = Number(params.get("end")) + if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) return undefined + return { + startLine, + endLine, + startChar: 0, + endChar: 0, + } +} + +function textPartValue(parts: Part[]) { + const candidates = parts + .filter((part): part is TextPart => part.type === "text") + .filter((part) => !part.synthetic && !part.ignored) + return candidates.reduce((best: TextPart | undefined, part) => { + if (!best) return part + if (part.text.length > best.text.length) return part + return best + }, undefined) +} + +/** + * Extract prompt content from message parts for restoring into the prompt input. + * This is used by undo to restore the original user prompt. + */ +export function extractPromptFromParts(parts: Part[], opts?: { directory?: string; attachmentName?: string }): Prompt { + const textPart = textPartValue(parts) + const text = textPart?.text ?? "" + const directory = opts?.directory + const attachmentName = opts?.attachmentName ?? "attachment" + + const toRelative = (path: string) => { + if (!directory) return path + + const prefix = directory.endsWith("/") ? directory : directory + "/" + if (path.startsWith(prefix)) return path.slice(prefix.length) + + if (path.startsWith(directory)) { + const next = path.slice(directory.length) + if (next.startsWith("/")) return next.slice(1) + return next + } + + return path + } + + const inline: Inline[] = [] + const images: ImageAttachmentPart[] = [] + + for (const part of parts) { + if (part.type === "file") { + const filePart = part as FilePart + const sourceText = filePart.source?.text + if (sourceText) { + const value = sourceText.value + const start = sourceText.start + const end = sourceText.end + let path = value + if (value.startsWith("@")) path = value.slice(1) + if (!value.startsWith("@") && filePart.source && "path" in filePart.source) { + path = filePart.source.path + } + inline.push({ + type: "file", + start, + end, + value, + path: toRelative(path), + selection: selectionFromFileUrl(filePart.url), + }) + continue + } + + if (filePart.url.startsWith("data:")) { + images.push({ + type: "image", + id: filePart.id, + filename: filePart.filename ?? attachmentName, + mime: filePart.mime, + dataUrl: filePart.url, + }) + } + } + + if (part.type === "agent") { + const agentPart = part as MessageAgentPart + const source = agentPart.source + if (!source) continue + inline.push({ + type: "agent", + start: source.start, + end: source.end, + value: source.value, + name: agentPart.name, + }) + } + } + + inline.sort((a, b) => { + if (a.start !== b.start) return a.start - b.start + return a.end - b.end + }) + + const result: Prompt = [] + let position = 0 + let cursor = 0 + + const pushText = (content: string) => { + if (!content) return + result.push({ + type: "text", + content, + start: position, + end: position + content.length, + }) + position += content.length + } + + const pushFile = (item: Extract) => { + const content = item.value + const attachment: FileAttachmentPart = { + type: "file", + path: item.path, + content, + start: position, + end: position + content.length, + selection: item.selection, + } + result.push(attachment) + position += content.length + } + + const pushAgent = (item: Extract) => { + const content = item.value + const mention: AgentPart = { + type: "agent", + name: item.name, + content, + start: position, + end: position + content.length, + } + result.push(mention) + position += content.length + } + + for (const item of inline) { + if (item.start < 0 || item.end < item.start) continue + + const expected = item.value + if (!expected) continue + + const mismatch = item.end > text.length || item.start < cursor || text.slice(item.start, item.end) !== expected + const start = mismatch ? text.indexOf(expected, cursor) : item.start + if (start === -1) continue + const end = mismatch ? start + expected.length : item.end + + pushText(text.slice(cursor, start)) + + if (item.type === "file") pushFile(item) + if (item.type === "agent") pushAgent(item) + + cursor = end + } + + pushText(text.slice(cursor)) + + if (result.length === 0) { + result.push({ type: "text", content: "", start: 0, end: 0 }) + } + + if (images.length === 0) return result + return [...result, ...images] +} diff --git a/packages/app/src/utils/same.ts b/packages/app/src/utils/same.ts new file mode 100644 index 00000000000..c956f92998a --- /dev/null +++ b/packages/app/src/utils/same.ts @@ -0,0 +1,6 @@ +export function same(a: readonly T[] | undefined, b: readonly T[] | undefined) { + if (a === b) return true + if (!a || !b) return false + if (a.length !== b.length) return false + return a.every((x, i) => x === b[i]) +} diff --git a/packages/app/src/utils/solid-dnd.tsx b/packages/app/src/utils/solid-dnd.tsx new file mode 100644 index 00000000000..a634be4b486 --- /dev/null +++ b/packages/app/src/utils/solid-dnd.tsx @@ -0,0 +1,55 @@ +import { useDragDropContext } from "@thisbeyond/solid-dnd" +import { JSXElement } from "solid-js" +import type { Transformer } from "@thisbeyond/solid-dnd" + +export const getDraggableId = (event: unknown): string | undefined => { + if (typeof event !== "object" || event === null) return undefined + if (!("draggable" in event)) return undefined + const draggable = (event as { draggable?: { id?: unknown } }).draggable + if (!draggable) return undefined + return typeof draggable.id === "string" ? draggable.id : undefined +} + +export const ConstrainDragXAxis = (): JSXElement => { + const context = useDragDropContext() + if (!context) return <> + const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context + const transformer: Transformer = { + id: "constrain-x-axis", + order: 100, + callback: (transform) => ({ ...transform, x: 0 }), + } + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) + }) + return <> +} + +export const ConstrainDragYAxis = (): JSXElement => { + const context = useDragDropContext() + if (!context) return <> + const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context + const transformer: Transformer = { + id: "constrain-y-axis", + order: 100, + callback: (transform) => ({ ...transform, y: 0 }), + } + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) + }) + return <> +} diff --git a/packages/app/src/utils/sound.ts b/packages/app/src/utils/sound.ts new file mode 100644 index 00000000000..d5e606c6750 --- /dev/null +++ b/packages/app/src/utils/sound.ts @@ -0,0 +1,110 @@ +import alert01 from "@opencode-ai/ui/audio/alert-01.aac" +import alert02 from "@opencode-ai/ui/audio/alert-02.aac" +import alert03 from "@opencode-ai/ui/audio/alert-03.aac" +import alert04 from "@opencode-ai/ui/audio/alert-04.aac" +import alert05 from "@opencode-ai/ui/audio/alert-05.aac" +import alert06 from "@opencode-ai/ui/audio/alert-06.aac" +import alert07 from "@opencode-ai/ui/audio/alert-07.aac" +import alert08 from "@opencode-ai/ui/audio/alert-08.aac" +import alert09 from "@opencode-ai/ui/audio/alert-09.aac" +import alert10 from "@opencode-ai/ui/audio/alert-10.aac" +import bipbop01 from "@opencode-ai/ui/audio/bip-bop-01.aac" +import bipbop02 from "@opencode-ai/ui/audio/bip-bop-02.aac" +import bipbop03 from "@opencode-ai/ui/audio/bip-bop-03.aac" +import bipbop04 from "@opencode-ai/ui/audio/bip-bop-04.aac" +import bipbop05 from "@opencode-ai/ui/audio/bip-bop-05.aac" +import bipbop06 from "@opencode-ai/ui/audio/bip-bop-06.aac" +import bipbop07 from "@opencode-ai/ui/audio/bip-bop-07.aac" +import bipbop08 from "@opencode-ai/ui/audio/bip-bop-08.aac" +import bipbop09 from "@opencode-ai/ui/audio/bip-bop-09.aac" +import bipbop10 from "@opencode-ai/ui/audio/bip-bop-10.aac" +import nope01 from "@opencode-ai/ui/audio/nope-01.aac" +import nope02 from "@opencode-ai/ui/audio/nope-02.aac" +import nope03 from "@opencode-ai/ui/audio/nope-03.aac" +import nope04 from "@opencode-ai/ui/audio/nope-04.aac" +import nope05 from "@opencode-ai/ui/audio/nope-05.aac" +import nope06 from "@opencode-ai/ui/audio/nope-06.aac" +import nope07 from "@opencode-ai/ui/audio/nope-07.aac" +import nope08 from "@opencode-ai/ui/audio/nope-08.aac" +import nope09 from "@opencode-ai/ui/audio/nope-09.aac" +import nope10 from "@opencode-ai/ui/audio/nope-10.aac" +import nope11 from "@opencode-ai/ui/audio/nope-11.aac" +import nope12 from "@opencode-ai/ui/audio/nope-12.aac" +import staplebops01 from "@opencode-ai/ui/audio/staplebops-01.aac" +import staplebops02 from "@opencode-ai/ui/audio/staplebops-02.aac" +import staplebops03 from "@opencode-ai/ui/audio/staplebops-03.aac" +import staplebops04 from "@opencode-ai/ui/audio/staplebops-04.aac" +import staplebops05 from "@opencode-ai/ui/audio/staplebops-05.aac" +import staplebops06 from "@opencode-ai/ui/audio/staplebops-06.aac" +import staplebops07 from "@opencode-ai/ui/audio/staplebops-07.aac" +import yup01 from "@opencode-ai/ui/audio/yup-01.aac" +import yup02 from "@opencode-ai/ui/audio/yup-02.aac" +import yup03 from "@opencode-ai/ui/audio/yup-03.aac" +import yup04 from "@opencode-ai/ui/audio/yup-04.aac" +import yup05 from "@opencode-ai/ui/audio/yup-05.aac" +import yup06 from "@opencode-ai/ui/audio/yup-06.aac" + +export const SOUND_OPTIONS = [ + { id: "alert-01", label: "sound.option.alert01", src: alert01 }, + { id: "alert-02", label: "sound.option.alert02", src: alert02 }, + { id: "alert-03", label: "sound.option.alert03", src: alert03 }, + { id: "alert-04", label: "sound.option.alert04", src: alert04 }, + { id: "alert-05", label: "sound.option.alert05", src: alert05 }, + { id: "alert-06", label: "sound.option.alert06", src: alert06 }, + { id: "alert-07", label: "sound.option.alert07", src: alert07 }, + { id: "alert-08", label: "sound.option.alert08", src: alert08 }, + { id: "alert-09", label: "sound.option.alert09", src: alert09 }, + { id: "alert-10", label: "sound.option.alert10", src: alert10 }, + { id: "bip-bop-01", label: "sound.option.bipbop01", src: bipbop01 }, + { id: "bip-bop-02", label: "sound.option.bipbop02", src: bipbop02 }, + { id: "bip-bop-03", label: "sound.option.bipbop03", src: bipbop03 }, + { id: "bip-bop-04", label: "sound.option.bipbop04", src: bipbop04 }, + { id: "bip-bop-05", label: "sound.option.bipbop05", src: bipbop05 }, + { id: "bip-bop-06", label: "sound.option.bipbop06", src: bipbop06 }, + { id: "bip-bop-07", label: "sound.option.bipbop07", src: bipbop07 }, + { id: "bip-bop-08", label: "sound.option.bipbop08", src: bipbop08 }, + { id: "bip-bop-09", label: "sound.option.bipbop09", src: bipbop09 }, + { id: "bip-bop-10", label: "sound.option.bipbop10", src: bipbop10 }, + { id: "staplebops-01", label: "sound.option.staplebops01", src: staplebops01 }, + { id: "staplebops-02", label: "sound.option.staplebops02", src: staplebops02 }, + { id: "staplebops-03", label: "sound.option.staplebops03", src: staplebops03 }, + { id: "staplebops-04", label: "sound.option.staplebops04", src: staplebops04 }, + { id: "staplebops-05", label: "sound.option.staplebops05", src: staplebops05 }, + { id: "staplebops-06", label: "sound.option.staplebops06", src: staplebops06 }, + { id: "staplebops-07", label: "sound.option.staplebops07", src: staplebops07 }, + { id: "nope-01", label: "sound.option.nope01", src: nope01 }, + { id: "nope-02", label: "sound.option.nope02", src: nope02 }, + { id: "nope-03", label: "sound.option.nope03", src: nope03 }, + { id: "nope-04", label: "sound.option.nope04", src: nope04 }, + { id: "nope-05", label: "sound.option.nope05", src: nope05 }, + { id: "nope-06", label: "sound.option.nope06", src: nope06 }, + { id: "nope-07", label: "sound.option.nope07", src: nope07 }, + { id: "nope-08", label: "sound.option.nope08", src: nope08 }, + { id: "nope-09", label: "sound.option.nope09", src: nope09 }, + { id: "nope-10", label: "sound.option.nope10", src: nope10 }, + { id: "nope-11", label: "sound.option.nope11", src: nope11 }, + { id: "nope-12", label: "sound.option.nope12", src: nope12 }, + { id: "yup-01", label: "sound.option.yup01", src: yup01 }, + { id: "yup-02", label: "sound.option.yup02", src: yup02 }, + { id: "yup-03", label: "sound.option.yup03", src: yup03 }, + { id: "yup-04", label: "sound.option.yup04", src: yup04 }, + { id: "yup-05", label: "sound.option.yup05", src: yup05 }, + { id: "yup-06", label: "sound.option.yup06", src: yup06 }, +] as const + +export type SoundOption = (typeof SOUND_OPTIONS)[number] +export type SoundID = SoundOption["id"] + +const soundById = Object.fromEntries(SOUND_OPTIONS.map((s) => [s.id, s.src])) as Record + +export function soundSrc(id: string | undefined) { + if (!id) return + if (!(id in soundById)) return + return soundById[id as SoundID] +} + +export function playSound(src: string | undefined) { + if (typeof Audio === "undefined") return + if (!src) return + void new Audio(src).play().catch(() => undefined) +} diff --git a/packages/app/src/utils/speech.ts b/packages/app/src/utils/speech.ts new file mode 100644 index 00000000000..921e0a159bc --- /dev/null +++ b/packages/app/src/utils/speech.ts @@ -0,0 +1,302 @@ +import { createSignal, onCleanup } from "solid-js" + +// Minimal types to avoid relying on non-standard DOM typings +type RecognitionResult = { + 0: { transcript: string } + isFinal: boolean +} + +type RecognitionEvent = { + results: RecognitionResult[] + resultIndex: number +} + +interface Recognition { + continuous: boolean + interimResults: boolean + lang: string + start: () => void + stop: () => void + onresult: ((e: RecognitionEvent) => void) | null + onerror: ((e: { error: string }) => void) | null + onend: (() => void) | null + onstart: (() => void) | null +} + +const COMMIT_DELAY = 250 + +const appendSegment = (base: string, addition: string) => { + const trimmed = addition.trim() + if (!trimmed) return base + if (!base) return trimmed + const needsSpace = /\S$/.test(base) && !/^[,.;!?]/.test(trimmed) + return `${base}${needsSpace ? " " : ""}${trimmed}` +} + +const extractSuffix = (committed: string, hypothesis: string) => { + const cleanHypothesis = hypothesis.trim() + if (!cleanHypothesis) return "" + const baseTokens = committed.trim() ? committed.trim().split(/\s+/) : [] + const hypothesisTokens = cleanHypothesis.split(/\s+/) + let index = 0 + while ( + index < baseTokens.length && + index < hypothesisTokens.length && + baseTokens[index] === hypothesisTokens[index] + ) { + index += 1 + } + if (index < baseTokens.length) return "" + return hypothesisTokens.slice(index).join(" ") +} + +export function createSpeechRecognition(opts?: { + lang?: string + onFinal?: (text: string) => void + onInterim?: (text: string) => void +}) { + const hasSupport = + typeof window !== "undefined" && + Boolean((window as any).webkitSpeechRecognition || (window as any).SpeechRecognition) + + const [isRecording, setIsRecording] = createSignal(false) + const [committed, setCommitted] = createSignal("") + const [interim, setInterim] = createSignal("") + + let recognition: Recognition | undefined + let shouldContinue = false + let committedText = "" + let sessionCommitted = "" + let pendingHypothesis = "" + let lastInterimSuffix = "" + let shrinkCandidate: string | undefined + let commitTimer: number | undefined + + const cancelPendingCommit = () => { + if (commitTimer === undefined) return + clearTimeout(commitTimer) + commitTimer = undefined + } + + const commitSegment = (segment: string) => { + const nextCommitted = appendSegment(committedText, segment) + if (nextCommitted === committedText) return + committedText = nextCommitted + setCommitted(committedText) + if (opts?.onFinal) opts.onFinal(segment.trim()) + } + + const promotePending = () => { + if (!pendingHypothesis) return + const suffix = extractSuffix(sessionCommitted, pendingHypothesis) + if (!suffix) { + pendingHypothesis = "" + return + } + sessionCommitted = appendSegment(sessionCommitted, suffix) + commitSegment(suffix) + pendingHypothesis = "" + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + if (opts?.onInterim) opts.onInterim("") + } + + const applyInterim = (suffix: string, hypothesis: string) => { + cancelPendingCommit() + pendingHypothesis = hypothesis + lastInterimSuffix = suffix + shrinkCandidate = undefined + setInterim(suffix) + if (opts?.onInterim) { + opts.onInterim(suffix ? appendSegment(committedText, suffix) : "") + } + if (!suffix) return + const snapshot = hypothesis + commitTimer = window.setTimeout(() => { + if (pendingHypothesis !== snapshot) return + const currentSuffix = extractSuffix(sessionCommitted, pendingHypothesis) + if (!currentSuffix) return + sessionCommitted = appendSegment(sessionCommitted, currentSuffix) + commitSegment(currentSuffix) + pendingHypothesis = "" + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + if (opts?.onInterim) opts.onInterim("") + }, COMMIT_DELAY) + } + + if (hasSupport) { + const Ctor: new () => Recognition = (window as any).webkitSpeechRecognition || (window as any).SpeechRecognition + + recognition = new Ctor() + recognition.continuous = false + recognition.interimResults = true + recognition.lang = opts?.lang || (typeof navigator !== "undefined" ? navigator.language : "en-US") + + recognition.onresult = (event: RecognitionEvent) => { + if (!event.results.length) return + + let aggregatedFinal = "" + let latestHypothesis = "" + + for (let i = 0; i < event.results.length; i += 1) { + const result = event.results[i] + const transcript = (result[0]?.transcript || "").trim() + if (!transcript) continue + if (result.isFinal) { + aggregatedFinal = appendSegment(aggregatedFinal, transcript) + } else { + latestHypothesis = transcript + } + } + + if (aggregatedFinal) { + cancelPendingCommit() + const finalSuffix = extractSuffix(sessionCommitted, aggregatedFinal) + if (finalSuffix) { + sessionCommitted = appendSegment(sessionCommitted, finalSuffix) + commitSegment(finalSuffix) + } + pendingHypothesis = "" + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + if (opts?.onInterim) opts.onInterim("") + return + } + + cancelPendingCommit() + + if (!latestHypothesis) { + shrinkCandidate = undefined + applyInterim("", "") + return + } + + const suffix = extractSuffix(sessionCommitted, latestHypothesis) + + if (!suffix) { + if (!lastInterimSuffix) { + shrinkCandidate = undefined + applyInterim("", latestHypothesis) + return + } + if (shrinkCandidate === "") { + applyInterim("", latestHypothesis) + return + } + shrinkCandidate = "" + pendingHypothesis = latestHypothesis + return + } + + if (lastInterimSuffix && suffix.length < lastInterimSuffix.length) { + if (shrinkCandidate === suffix) { + applyInterim(suffix, latestHypothesis) + return + } + shrinkCandidate = suffix + pendingHypothesis = latestHypothesis + return + } + + shrinkCandidate = undefined + applyInterim(suffix, latestHypothesis) + } + + recognition.onerror = (e: { error: string }) => { + cancelPendingCommit() + lastInterimSuffix = "" + shrinkCandidate = undefined + if (e.error === "no-speech" && shouldContinue) { + setInterim("") + if (opts?.onInterim) opts.onInterim("") + setTimeout(() => { + try { + recognition?.start() + } catch {} + }, 150) + return + } + shouldContinue = false + setIsRecording(false) + } + + recognition.onstart = () => { + sessionCommitted = "" + pendingHypothesis = "" + cancelPendingCommit() + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + if (opts?.onInterim) opts.onInterim("") + setIsRecording(true) + } + + recognition.onend = () => { + cancelPendingCommit() + lastInterimSuffix = "" + shrinkCandidate = undefined + setIsRecording(false) + if (shouldContinue) { + setTimeout(() => { + try { + recognition?.start() + } catch {} + }, 150) + } + } + } + + const start = () => { + if (!recognition) return + shouldContinue = true + sessionCommitted = "" + pendingHypothesis = "" + cancelPendingCommit() + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + try { + recognition.start() + } catch {} + } + + const stop = () => { + if (!recognition) return + shouldContinue = false + promotePending() + cancelPendingCommit() + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + if (opts?.onInterim) opts.onInterim("") + try { + recognition.stop() + } catch {} + } + + onCleanup(() => { + shouldContinue = false + promotePending() + cancelPendingCommit() + lastInterimSuffix = "" + shrinkCandidate = undefined + setInterim("") + if (opts?.onInterim) opts.onInterim("") + try { + recognition?.stop() + } catch {} + }) + + return { + isSupported: () => hasSupport, + isRecording, + committed, + interim, + start, + stop, + } +} diff --git a/cloud/app/sst-env.d.ts b/packages/app/sst-env.d.ts similarity index 100% rename from cloud/app/sst-env.d.ts rename to packages/app/sst-env.d.ts diff --git a/packages/app/tsconfig.json b/packages/app/tsconfig.json new file mode 100644 index 00000000000..e2a27dd5d8a --- /dev/null +++ b/packages/app/tsconfig.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "composite": true, + "target": "ESNext", + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "allowJs": true, + "resolveJsonModule": true, + "strict": true, + "noEmit": false, + "emitDeclarationOnly": true, + "outDir": "node_modules/.ts-dist", + "isolatedModules": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src", "package.json"], + "exclude": ["dist", "ts-dist"] +} diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts new file mode 100644 index 00000000000..6a29ae6345e --- /dev/null +++ b/packages/app/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from "vite" +import desktopPlugin from "./vite" + +export default defineConfig({ + plugins: [desktopPlugin] as any, + server: { + host: "0.0.0.0", + allowedHosts: true, + port: 3000, + }, + build: { + target: "esnext", + // sourcemap: true, + }, +}) diff --git a/packages/app/vite.js b/packages/app/vite.js new file mode 100644 index 00000000000..6b8fd61376c --- /dev/null +++ b/packages/app/vite.js @@ -0,0 +1,26 @@ +import solidPlugin from "vite-plugin-solid" +import tailwindcss from "@tailwindcss/vite" +import { fileURLToPath } from "url" + +/** + * @type {import("vite").PluginOption} + */ +export default [ + { + name: "opencode-desktop:config", + config() { + return { + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, + worker: { + format: "es", + }, + } + }, + }, + tailwindcss(), + solidPlugin(), +] diff --git a/packages/console/app/.gitignore b/packages/console/app/.gitignore new file mode 100644 index 00000000000..5033416b52a --- /dev/null +++ b/packages/console/app/.gitignore @@ -0,0 +1,30 @@ +dist +.wrangler +.output +.vercel +.netlify +app.config.timestamp_*.js + +# Environment +.env +.env*.local + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +*.launch +.settings/ + +# Temp +gitignore + +# Generated files +public/sitemap.xml + +# System Files +.DS_Store +Thumbs.db diff --git a/cloud/app/.opencode/agent/css.md b/packages/console/app/.opencode/agent/css.md similarity index 98% rename from cloud/app/.opencode/agent/css.md rename to packages/console/app/.opencode/agent/css.md index d0ec43a483b..d5e68c7bf6a 100644 --- a/cloud/app/.opencode/agent/css.md +++ b/packages/console/app/.opencode/agent/css.md @@ -49,7 +49,7 @@ use data attributes to represent different states of the component } ``` -this will allow jsx to control the syling +this will allow jsx to control the styling avoid selectors that just target an element type like `> span` you should assign it a slot name. it's ok to do this sometimes where it makes sense semantically diff --git a/cloud/app/README.md b/packages/console/app/README.md similarity index 100% rename from cloud/app/README.md rename to packages/console/app/README.md diff --git a/packages/console/app/package.json b/packages/console/app/package.json new file mode 100644 index 00000000000..1f68a2c3878 --- /dev/null +++ b/packages/console/app/package.json @@ -0,0 +1,46 @@ +{ + "name": "@opencode-ai/console-app", + "version": "1.1.32", + "type": "module", + "license": "MIT", + "scripts": { + "typecheck": "tsgo --noEmit", + "dev": "vite dev --host 0.0.0.0", + "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai VITE_STRIPE_PUBLISHABLE_KEY=pk_test_51RtuLNE7fOCwHSD4mewwzFejyytjdGoSDK7CAvhbffwaZnPbNb2rwJICw6LTOXCmWO320fSNXvb5NzI08RZVkAxd00syfqrW7t bun sst shell --stage=dev bun dev", + "build": "./script/generate-sitemap.ts && vite build && ../../opencode/script/schema.ts ./.output/public/config.json", + "start": "vite start" + }, + "dependencies": { + "@cloudflare/vite-plugin": "1.15.2", + "@ibm/plex": "6.4.1", + "@jsx-email/render": "1.1.1", + "@kobalte/core": "catalog:", + "@openauthjs/openauth": "catalog:", + "@opencode-ai/console-core": "workspace:*", + "@opencode-ai/console-mail": "workspace:*", + "@opencode-ai/console-resource": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@smithy/eventstream-codec": "4.2.7", + "@smithy/util-utf8": "4.2.0", + "@solidjs/meta": "catalog:", + "@solidjs/router": "catalog:", + "@solidjs/start": "catalog:", + "@stripe/stripe-js": "8.6.1", + "chart.js": "4.5.1", + "nitro": "3.0.1-alpha.1", + "solid-js": "catalog:", + "solid-list": "0.3.0", + "solid-stripe": "0.8.1", + "vite": "catalog:", + "zod": "catalog:" + }, + "devDependencies": { + "@typescript/native-preview": "catalog:", + "@webgpu/types": "0.1.54", + "typescript": "catalog:", + "wrangler": "4.50.0" + }, + "engines": { + "node": ">=22" + } +} diff --git a/packages/console/app/public/apple-touch-icon-v3.png b/packages/console/app/public/apple-touch-icon-v3.png new file mode 120000 index 00000000000..ddd1d1ac33c --- /dev/null +++ b/packages/console/app/public/apple-touch-icon-v3.png @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/apple-touch-icon-v3.png \ No newline at end of file diff --git a/packages/console/app/public/apple-touch-icon.png b/packages/console/app/public/apple-touch-icon.png new file mode 120000 index 00000000000..52ebd1c302c --- /dev/null +++ b/packages/console/app/public/apple-touch-icon.png @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/apple-touch-icon.png \ No newline at end of file diff --git a/packages/console/app/public/email b/packages/console/app/public/email new file mode 120000 index 00000000000..0df016d0197 --- /dev/null +++ b/packages/console/app/public/email @@ -0,0 +1 @@ +../../mail/emails/templates/static \ No newline at end of file diff --git a/packages/console/app/public/favicon-96x96-v3.png b/packages/console/app/public/favicon-96x96-v3.png new file mode 120000 index 00000000000..5f4b8a73bbf --- /dev/null +++ b/packages/console/app/public/favicon-96x96-v3.png @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon-96x96-v3.png \ No newline at end of file diff --git a/packages/console/app/public/favicon-96x96.png b/packages/console/app/public/favicon-96x96.png new file mode 120000 index 00000000000..0a40e561932 --- /dev/null +++ b/packages/console/app/public/favicon-96x96.png @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon-96x96.png \ No newline at end of file diff --git a/packages/console/app/public/favicon-v3.ico b/packages/console/app/public/favicon-v3.ico new file mode 120000 index 00000000000..6e1f48aec90 --- /dev/null +++ b/packages/console/app/public/favicon-v3.ico @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon-v3.ico \ No newline at end of file diff --git a/packages/console/app/public/favicon-v3.svg b/packages/console/app/public/favicon-v3.svg new file mode 120000 index 00000000000..77814acf5c1 --- /dev/null +++ b/packages/console/app/public/favicon-v3.svg @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon-v3.svg \ No newline at end of file diff --git a/packages/console/app/public/favicon.ico b/packages/console/app/public/favicon.ico new file mode 120000 index 00000000000..d861e771f8c --- /dev/null +++ b/packages/console/app/public/favicon.ico @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon.ico \ No newline at end of file diff --git a/packages/console/app/public/favicon.svg b/packages/console/app/public/favicon.svg new file mode 120000 index 00000000000..9a9c41c9215 --- /dev/null +++ b/packages/console/app/public/favicon.svg @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon.svg \ No newline at end of file diff --git a/packages/console/app/public/opencode-brand-assets.zip b/packages/console/app/public/opencode-brand-assets.zip new file mode 100644 index 00000000000..1a145bbe012 Binary files /dev/null and b/packages/console/app/public/opencode-brand-assets.zip differ diff --git a/packages/console/app/public/robots.txt b/packages/console/app/public/robots.txt new file mode 100644 index 00000000000..bddac69deae --- /dev/null +++ b/packages/console/app/public/robots.txt @@ -0,0 +1,6 @@ +User-agent: * +Allow: / + +# Disallow shared content pages +Disallow: /s/ +Disallow: /share/ \ No newline at end of file diff --git a/packages/console/app/public/site.webmanifest b/packages/console/app/public/site.webmanifest new file mode 120000 index 00000000000..ce3161b45e7 --- /dev/null +++ b/packages/console/app/public/site.webmanifest @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/site.webmanifest \ No newline at end of file diff --git a/packages/console/app/public/social-share-black.png b/packages/console/app/public/social-share-black.png new file mode 120000 index 00000000000..5baa00483b5 --- /dev/null +++ b/packages/console/app/public/social-share-black.png @@ -0,0 +1 @@ +../../../ui/src/assets/images/social-share-black.png \ No newline at end of file diff --git a/packages/console/app/public/social-share-zen.png b/packages/console/app/public/social-share-zen.png new file mode 120000 index 00000000000..2cb95c718ff --- /dev/null +++ b/packages/console/app/public/social-share-zen.png @@ -0,0 +1 @@ +../../../ui/src/assets/images/social-share-zen.png \ No newline at end of file diff --git a/packages/console/app/public/social-share.png b/packages/console/app/public/social-share.png new file mode 120000 index 00000000000..deb3346c2c5 --- /dev/null +++ b/packages/console/app/public/social-share.png @@ -0,0 +1 @@ +../../../ui/src/assets/images/social-share.png \ No newline at end of file diff --git a/packages/console/app/public/theme.json b/packages/console/app/public/theme.json new file mode 100644 index 00000000000..b3e97f7ca89 --- /dev/null +++ b/packages/console/app/public/theme.json @@ -0,0 +1,182 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "description": "JSON schema reference for configuration validation" + }, + "defs": { + "type": "object", + "description": "Color definitions that can be referenced in the theme", + "patternProperties": { + "^[a-zA-Z][a-zA-Z0-9_]*$": { + "oneOf": [ + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$", + "description": "Hex color value" + }, + { + "type": "integer", + "minimum": 0, + "maximum": 255, + "description": "ANSI color code (0-255)" + }, + { + "type": "string", + "enum": ["none"], + "description": "No color (uses terminal default)" + } + ] + } + }, + "additionalProperties": false + }, + "theme": { + "type": "object", + "description": "Theme color definitions", + "properties": { + "primary": { "$ref": "#/definitions/colorValue" }, + "secondary": { "$ref": "#/definitions/colorValue" }, + "accent": { "$ref": "#/definitions/colorValue" }, + "error": { "$ref": "#/definitions/colorValue" }, + "warning": { "$ref": "#/definitions/colorValue" }, + "success": { "$ref": "#/definitions/colorValue" }, + "info": { "$ref": "#/definitions/colorValue" }, + "text": { "$ref": "#/definitions/colorValue" }, + "textMuted": { "$ref": "#/definitions/colorValue" }, + "background": { "$ref": "#/definitions/colorValue" }, + "backgroundPanel": { "$ref": "#/definitions/colorValue" }, + "backgroundElement": { "$ref": "#/definitions/colorValue" }, + "border": { "$ref": "#/definitions/colorValue" }, + "borderActive": { "$ref": "#/definitions/colorValue" }, + "borderSubtle": { "$ref": "#/definitions/colorValue" }, + "diffAdded": { "$ref": "#/definitions/colorValue" }, + "diffRemoved": { "$ref": "#/definitions/colorValue" }, + "diffContext": { "$ref": "#/definitions/colorValue" }, + "diffHunkHeader": { "$ref": "#/definitions/colorValue" }, + "diffHighlightAdded": { "$ref": "#/definitions/colorValue" }, + "diffHighlightRemoved": { "$ref": "#/definitions/colorValue" }, + "diffAddedBg": { "$ref": "#/definitions/colorValue" }, + "diffRemovedBg": { "$ref": "#/definitions/colorValue" }, + "diffContextBg": { "$ref": "#/definitions/colorValue" }, + "diffLineNumber": { "$ref": "#/definitions/colorValue" }, + "diffAddedLineNumberBg": { "$ref": "#/definitions/colorValue" }, + "diffRemovedLineNumberBg": { "$ref": "#/definitions/colorValue" }, + "markdownText": { "$ref": "#/definitions/colorValue" }, + "markdownHeading": { "$ref": "#/definitions/colorValue" }, + "markdownLink": { "$ref": "#/definitions/colorValue" }, + "markdownLinkText": { "$ref": "#/definitions/colorValue" }, + "markdownCode": { "$ref": "#/definitions/colorValue" }, + "markdownBlockQuote": { "$ref": "#/definitions/colorValue" }, + "markdownEmph": { "$ref": "#/definitions/colorValue" }, + "markdownStrong": { "$ref": "#/definitions/colorValue" }, + "markdownHorizontalRule": { "$ref": "#/definitions/colorValue" }, + "markdownListItem": { "$ref": "#/definitions/colorValue" }, + "markdownListEnumeration": { "$ref": "#/definitions/colorValue" }, + "markdownImage": { "$ref": "#/definitions/colorValue" }, + "markdownImageText": { "$ref": "#/definitions/colorValue" }, + "markdownCodeBlock": { "$ref": "#/definitions/colorValue" }, + "syntaxComment": { "$ref": "#/definitions/colorValue" }, + "syntaxKeyword": { "$ref": "#/definitions/colorValue" }, + "syntaxFunction": { "$ref": "#/definitions/colorValue" }, + "syntaxVariable": { "$ref": "#/definitions/colorValue" }, + "syntaxString": { "$ref": "#/definitions/colorValue" }, + "syntaxNumber": { "$ref": "#/definitions/colorValue" }, + "syntaxType": { "$ref": "#/definitions/colorValue" }, + "syntaxOperator": { "$ref": "#/definitions/colorValue" }, + "syntaxPunctuation": { "$ref": "#/definitions/colorValue" } + }, + "required": ["primary", "secondary", "accent", "text", "textMuted", "background"], + "additionalProperties": false + } + }, + "required": ["theme"], + "additionalProperties": false, + "definitions": { + "colorValue": { + "oneOf": [ + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$", + "description": "Hex color value (same for dark and light)" + }, + { + "type": "integer", + "minimum": 0, + "maximum": 255, + "description": "ANSI color code (0-255, same for dark and light)" + }, + { + "type": "string", + "enum": ["none"], + "description": "No color (uses terminal default)" + }, + { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "description": "Reference to another color in the theme or defs" + }, + { + "type": "object", + "properties": { + "dark": { + "oneOf": [ + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$", + "description": "Hex color value for dark mode" + }, + { + "type": "integer", + "minimum": 0, + "maximum": 255, + "description": "ANSI color code for dark mode" + }, + { + "type": "string", + "enum": ["none"], + "description": "No color (uses terminal default)" + }, + { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "description": "Reference to another color for dark mode" + } + ] + }, + "light": { + "oneOf": [ + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$", + "description": "Hex color value for light mode" + }, + { + "type": "integer", + "minimum": 0, + "maximum": 255, + "description": "ANSI color code for light mode" + }, + { + "type": "string", + "enum": ["none"], + "description": "No color (uses terminal default)" + }, + { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "description": "Reference to another color for light mode" + } + ] + } + }, + "required": ["dark", "light"], + "additionalProperties": false, + "description": "Separate colors for dark and light modes" + } + ] + } + } +} diff --git a/packages/console/app/public/web-app-manifest-192x192.png b/packages/console/app/public/web-app-manifest-192x192.png new file mode 120000 index 00000000000..9d3590fc2b0 --- /dev/null +++ b/packages/console/app/public/web-app-manifest-192x192.png @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/web-app-manifest-192x192.png \ No newline at end of file diff --git a/packages/console/app/public/web-app-manifest-512x512.png b/packages/console/app/public/web-app-manifest-512x512.png new file mode 120000 index 00000000000..0ca44b8899b --- /dev/null +++ b/packages/console/app/public/web-app-manifest-512x512.png @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/web-app-manifest-512x512.png \ No newline at end of file diff --git a/packages/console/app/script/generate-sitemap.ts b/packages/console/app/script/generate-sitemap.ts new file mode 100755 index 00000000000..6cbffcb8516 --- /dev/null +++ b/packages/console/app/script/generate-sitemap.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env bun +import { readdir, writeFile } from "fs/promises" +import { join, dirname } from "path" +import { fileURLToPath } from "url" +import { config } from "../src/config.js" + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const BASE_URL = config.baseUrl +const PUBLIC_DIR = join(__dirname, "../public") +const ROUTES_DIR = join(__dirname, "../src/routes") +const DOCS_DIR = join(__dirname, "../../../web/src/content/docs") + +interface SitemapEntry { + url: string + priority: number + changefreq: string +} + +async function getMainRoutes(): Promise { + const routes: SitemapEntry[] = [] + + // Add main static routes + const staticRoutes = [ + { path: "/", priority: 1.0, changefreq: "daily" }, + { path: "/enterprise", priority: 0.8, changefreq: "weekly" }, + { path: "/brand", priority: 0.6, changefreq: "monthly" }, + { path: "/zen", priority: 0.8, changefreq: "weekly" }, + ] + + for (const route of staticRoutes) { + routes.push({ + url: `${BASE_URL}${route.path}`, + priority: route.priority, + changefreq: route.changefreq, + }) + } + + return routes +} + +async function getDocsRoutes(): Promise { + const routes: SitemapEntry[] = [] + + try { + const files = await readdir(DOCS_DIR) + + for (const file of files) { + if (!file.endsWith(".mdx")) continue + + const slug = file.replace(".mdx", "") + const path = slug === "index" ? "/docs/" : `/docs/${slug}` + + routes.push({ + url: `${BASE_URL}${path}`, + priority: slug === "index" ? 0.9 : 0.7, + changefreq: "weekly", + }) + } + } catch (error) { + console.error("Error reading docs directory:", error) + } + + return routes +} + +function generateSitemapXML(entries: SitemapEntry[]): string { + const urls = entries + .map( + (entry) => ` + ${entry.url} + ${entry.changefreq} + ${entry.priority} + `, + ) + .join("\n") + + return ` + +${urls} +` +} + +async function main() { + console.log("Generating sitemap...") + + const mainRoutes = await getMainRoutes() + const docsRoutes = await getDocsRoutes() + + const allRoutes = [...mainRoutes, ...docsRoutes] + + console.log(`Found ${mainRoutes.length} main routes`) + console.log(`Found ${docsRoutes.length} docs routes`) + console.log(`Total: ${allRoutes.length} routes`) + + const xml = generateSitemapXML(allRoutes) + + const outputPath = join(PUBLIC_DIR, "sitemap.xml") + await writeFile(outputPath, xml, "utf-8") + + console.log(`✓ Sitemap generated at ${outputPath}`) +} + +main() diff --git a/cloud/app/src/app.css b/packages/console/app/src/app.css similarity index 100% rename from cloud/app/src/app.css rename to packages/console/app/src/app.css diff --git a/packages/console/app/src/app.tsx b/packages/console/app/src/app.tsx new file mode 100644 index 00000000000..cde2f01876f --- /dev/null +++ b/packages/console/app/src/app.tsx @@ -0,0 +1,27 @@ +import { MetaProvider, Title, Meta } from "@solidjs/meta" +import { Router } from "@solidjs/router" +import { FileRoutes } from "@solidjs/start/router" +import { Suspense } from "solid-js" +import { Favicon } from "@opencode-ai/ui/favicon" +import { Font } from "@opencode-ai/ui/font" +import "@ibm/plex/css/ibm-plex.css" +import "./app.css" + +export default function App() { + return ( + ( + + opencode + + + + {props.children} + + )} + > + + + ) +} diff --git a/packages/console/app/src/asset/black/hero.png b/packages/console/app/src/asset/black/hero.png new file mode 100644 index 00000000000..967f4ac6e50 Binary files /dev/null and b/packages/console/app/src/asset/black/hero.png differ diff --git a/packages/console/app/src/asset/brand/opencode-brand-assets.zip b/packages/console/app/src/asset/brand/opencode-brand-assets.zip new file mode 100644 index 00000000000..85d3635ac46 Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-brand-assets.zip differ diff --git a/packages/console/app/src/asset/brand/opencode-logo-dark.png b/packages/console/app/src/asset/brand/opencode-logo-dark.png new file mode 100644 index 00000000000..cf868c8e871 Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-logo-dark.png differ diff --git a/packages/console/app/src/asset/brand/opencode-logo-dark.svg b/packages/console/app/src/asset/brand/opencode-logo-dark.svg new file mode 100644 index 00000000000..c28babff1be --- /dev/null +++ b/packages/console/app/src/asset/brand/opencode-logo-dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/brand/opencode-logo-light.png b/packages/console/app/src/asset/brand/opencode-logo-light.png new file mode 100644 index 00000000000..a2ffc9b90b2 Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-logo-light.png differ diff --git a/packages/console/app/src/asset/brand/opencode-logo-light.svg b/packages/console/app/src/asset/brand/opencode-logo-light.svg new file mode 100644 index 00000000000..7ed0af003bb --- /dev/null +++ b/packages/console/app/src/asset/brand/opencode-logo-light.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-dark.png b/packages/console/app/src/asset/brand/opencode-wordmark-dark.png new file mode 100644 index 00000000000..f8e2c3f4042 Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-wordmark-dark.png differ diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-dark.svg b/packages/console/app/src/asset/brand/opencode-wordmark-dark.svg new file mode 100644 index 00000000000..a242eeeab12 --- /dev/null +++ b/packages/console/app/src/asset/brand/opencode-wordmark-dark.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-light.png b/packages/console/app/src/asset/brand/opencode-wordmark-light.png new file mode 100644 index 00000000000..f53607f717c Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-wordmark-light.png differ diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-light.svg b/packages/console/app/src/asset/brand/opencode-wordmark-light.svg new file mode 100644 index 00000000000..24a36c7ce7f --- /dev/null +++ b/packages/console/app/src/asset/brand/opencode-wordmark-light.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-simple-dark.png b/packages/console/app/src/asset/brand/opencode-wordmark-simple-dark.png new file mode 100644 index 00000000000..945d4eb3990 Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-wordmark-simple-dark.png differ diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-simple-dark.svg b/packages/console/app/src/asset/brand/opencode-wordmark-simple-dark.svg new file mode 100644 index 00000000000..afc323e4d55 --- /dev/null +++ b/packages/console/app/src/asset/brand/opencode-wordmark-simple-dark.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-simple-light.png b/packages/console/app/src/asset/brand/opencode-wordmark-simple-light.png new file mode 100644 index 00000000000..6c1d05704ad Binary files /dev/null and b/packages/console/app/src/asset/brand/opencode-wordmark-simple-light.png differ diff --git a/packages/console/app/src/asset/brand/opencode-wordmark-simple-light.svg b/packages/console/app/src/asset/brand/opencode-wordmark-simple-light.svg new file mode 100644 index 00000000000..29be24534d2 --- /dev/null +++ b/packages/console/app/src/asset/brand/opencode-wordmark-simple-light.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/brand/preview-opencode-dark.png b/packages/console/app/src/asset/brand/preview-opencode-dark.png new file mode 100644 index 00000000000..3c19242a80d Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-dark.png differ diff --git a/packages/console/app/src/asset/brand/preview-opencode-logo-dark.png b/packages/console/app/src/asset/brand/preview-opencode-logo-dark.png new file mode 100644 index 00000000000..d1ef7137216 Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-logo-dark.png differ diff --git a/packages/console/app/src/asset/brand/preview-opencode-logo-light.png b/packages/console/app/src/asset/brand/preview-opencode-logo-light.png new file mode 100644 index 00000000000..d77bbc38a10 Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-logo-light.png differ diff --git a/packages/console/app/src/asset/brand/preview-opencode-wordmark-dark.png b/packages/console/app/src/asset/brand/preview-opencode-wordmark-dark.png new file mode 100644 index 00000000000..58bcf936fbb Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-wordmark-dark.png differ diff --git a/packages/console/app/src/asset/brand/preview-opencode-wordmark-light.png b/packages/console/app/src/asset/brand/preview-opencode-wordmark-light.png new file mode 100644 index 00000000000..b39b7997d19 Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-wordmark-light.png differ diff --git a/packages/console/app/src/asset/brand/preview-opencode-wordmark-simple-dark.png b/packages/console/app/src/asset/brand/preview-opencode-wordmark-simple-dark.png new file mode 100644 index 00000000000..2910c7a28ab Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-wordmark-simple-dark.png differ diff --git a/packages/console/app/src/asset/brand/preview-opencode-wordmark-simple-light.png b/packages/console/app/src/asset/brand/preview-opencode-wordmark-simple-light.png new file mode 100644 index 00000000000..6ab84aa5831 Binary files /dev/null and b/packages/console/app/src/asset/brand/preview-opencode-wordmark-simple-light.png differ diff --git a/packages/console/app/src/asset/lander/avatar-adam.png b/packages/console/app/src/asset/lander/avatar-adam.png new file mode 100644 index 00000000000..d94a0a9a4c1 Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-adam.png differ diff --git a/packages/console/app/src/asset/lander/avatar-david.png b/packages/console/app/src/asset/lander/avatar-david.png new file mode 100644 index 00000000000..2e65272e351 Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-david.png differ diff --git a/packages/console/app/src/asset/lander/avatar-dax.png b/packages/console/app/src/asset/lander/avatar-dax.png new file mode 100644 index 00000000000..0ee8feace63 Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-dax.png differ diff --git a/packages/console/app/src/asset/lander/avatar-frank.png b/packages/console/app/src/asset/lander/avatar-frank.png new file mode 100644 index 00000000000..5e8f7715f22 Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-frank.png differ diff --git a/packages/console/app/src/asset/lander/avatar-jay.png b/packages/console/app/src/asset/lander/avatar-jay.png new file mode 100644 index 00000000000..2f74ca8dc1e Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-jay.png differ diff --git a/packages/console/app/src/asset/lander/brand-assets-dark.svg b/packages/console/app/src/asset/lander/brand-assets-dark.svg new file mode 100644 index 00000000000..93da2462d9e --- /dev/null +++ b/packages/console/app/src/asset/lander/brand-assets-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/brand-assets-light.svg b/packages/console/app/src/asset/lander/brand-assets-light.svg new file mode 100644 index 00000000000..aa9d115bfc9 --- /dev/null +++ b/packages/console/app/src/asset/lander/brand-assets-light.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/brand.png b/packages/console/app/src/asset/lander/brand.png new file mode 100644 index 00000000000..9c1653ed007 Binary files /dev/null and b/packages/console/app/src/asset/lander/brand.png differ diff --git a/packages/console/app/src/asset/lander/check.svg b/packages/console/app/src/asset/lander/check.svg new file mode 100644 index 00000000000..0ac7759ea56 --- /dev/null +++ b/packages/console/app/src/asset/lander/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/console/app/src/asset/lander/copy.svg b/packages/console/app/src/asset/lander/copy.svg new file mode 100644 index 00000000000..e2263279e5e --- /dev/null +++ b/packages/console/app/src/asset/lander/copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/console/app/src/asset/lander/desktop-app-icon.png b/packages/console/app/src/asset/lander/desktop-app-icon.png new file mode 100644 index 00000000000..a35c28f516c Binary files /dev/null and b/packages/console/app/src/asset/lander/desktop-app-icon.png differ diff --git a/packages/console/app/src/asset/lander/dock.png b/packages/console/app/src/asset/lander/dock.png new file mode 100644 index 00000000000..b53db0106d9 Binary files /dev/null and b/packages/console/app/src/asset/lander/dock.png differ diff --git a/packages/console/app/src/asset/lander/logo-dark.svg b/packages/console/app/src/asset/lander/logo-dark.svg new file mode 100644 index 00000000000..d73830f9313 --- /dev/null +++ b/packages/console/app/src/asset/lander/logo-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/logo-light.svg b/packages/console/app/src/asset/lander/logo-light.svg new file mode 100644 index 00000000000..7394bf43256 --- /dev/null +++ b/packages/console/app/src/asset/lander/logo-light.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/opencode-comparison-min.mp4 b/packages/console/app/src/asset/lander/opencode-comparison-min.mp4 new file mode 100644 index 00000000000..3cfa15b3630 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-comparison-min.mp4 differ diff --git a/packages/console/app/src/asset/lander/opencode-comparison-poster.png b/packages/console/app/src/asset/lander/opencode-comparison-poster.png new file mode 100644 index 00000000000..e1cd4bd75f8 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-comparison-poster.png differ diff --git a/packages/console/app/src/asset/lander/opencode-desktop-icon.png b/packages/console/app/src/asset/lander/opencode-desktop-icon.png new file mode 100644 index 00000000000..f2c8d4f5a30 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-desktop-icon.png differ diff --git a/packages/console/app/src/asset/lander/opencode-logo-dark.svg b/packages/console/app/src/asset/lander/opencode-logo-dark.svg new file mode 100644 index 00000000000..154000aaa58 --- /dev/null +++ b/packages/console/app/src/asset/lander/opencode-logo-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/opencode-logo-light.svg b/packages/console/app/src/asset/lander/opencode-logo-light.svg new file mode 100644 index 00000000000..c1259a77def --- /dev/null +++ b/packages/console/app/src/asset/lander/opencode-logo-light.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/opencode-min.mp4 b/packages/console/app/src/asset/lander/opencode-min.mp4 new file mode 100644 index 00000000000..ffd6c4f7af4 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-min.mp4 differ diff --git a/packages/console/app/src/asset/lander/opencode-poster.png b/packages/console/app/src/asset/lander/opencode-poster.png new file mode 100644 index 00000000000..e1cd4bd75f8 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-poster.png differ diff --git a/packages/console/app/src/asset/lander/opencode-wordmark-dark.svg b/packages/console/app/src/asset/lander/opencode-wordmark-dark.svg new file mode 100644 index 00000000000..822d971ad8e --- /dev/null +++ b/packages/console/app/src/asset/lander/opencode-wordmark-dark.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/opencode-wordmark-light.svg b/packages/console/app/src/asset/lander/opencode-wordmark-light.svg new file mode 100644 index 00000000000..6d98af7004f --- /dev/null +++ b/packages/console/app/src/asset/lander/opencode-wordmark-light.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/lander/screenshot-github.png b/packages/console/app/src/asset/lander/screenshot-github.png new file mode 100644 index 00000000000..a421598ee58 Binary files /dev/null and b/packages/console/app/src/asset/lander/screenshot-github.png differ diff --git a/packages/console/app/src/asset/lander/screenshot-splash.png b/packages/console/app/src/asset/lander/screenshot-splash.png new file mode 100644 index 00000000000..98e9b477c9e Binary files /dev/null and b/packages/console/app/src/asset/lander/screenshot-splash.png differ diff --git a/packages/console/app/src/asset/lander/screenshot-vscode.png b/packages/console/app/src/asset/lander/screenshot-vscode.png new file mode 100644 index 00000000000..4297948e5d5 Binary files /dev/null and b/packages/console/app/src/asset/lander/screenshot-vscode.png differ diff --git a/packages/console/app/src/asset/lander/screenshot.png b/packages/console/app/src/asset/lander/screenshot.png new file mode 100644 index 00000000000..26975bc89fd Binary files /dev/null and b/packages/console/app/src/asset/lander/screenshot.png differ diff --git a/packages/console/app/src/asset/lander/wordmark-dark.svg b/packages/console/app/src/asset/lander/wordmark-dark.svg new file mode 100644 index 00000000000..42f8e22a6dc --- /dev/null +++ b/packages/console/app/src/asset/lander/wordmark-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/console/app/src/asset/lander/wordmark-light.svg b/packages/console/app/src/asset/lander/wordmark-light.svg new file mode 100644 index 00000000000..398278da690 --- /dev/null +++ b/packages/console/app/src/asset/lander/wordmark-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/console/app/src/asset/logo-ornate-dark.svg b/packages/console/app/src/asset/logo-ornate-dark.svg new file mode 100644 index 00000000000..a1582732423 --- /dev/null +++ b/packages/console/app/src/asset/logo-ornate-dark.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/logo-ornate-light.svg b/packages/console/app/src/asset/logo-ornate-light.svg new file mode 100644 index 00000000000..2a856dccefe --- /dev/null +++ b/packages/console/app/src/asset/logo-ornate-light.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/logo.svg b/packages/console/app/src/asset/logo.svg new file mode 100644 index 00000000000..2a856dccefe --- /dev/null +++ b/packages/console/app/src/asset/logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/zen-ornate-dark.svg b/packages/console/app/src/asset/zen-ornate-dark.svg new file mode 100644 index 00000000000..cdc4485fc59 --- /dev/null +++ b/packages/console/app/src/asset/zen-ornate-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/console/app/src/asset/zen-ornate-light.svg b/packages/console/app/src/asset/zen-ornate-light.svg new file mode 100644 index 00000000000..2a9ed13421e --- /dev/null +++ b/packages/console/app/src/asset/zen-ornate-light.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/console/app/src/component/dropdown.css b/packages/console/app/src/component/dropdown.css new file mode 100644 index 00000000000..242940e6aa4 --- /dev/null +++ b/packages/console/app/src/component/dropdown.css @@ -0,0 +1,80 @@ +[data-component="dropdown"] { + position: relative; + + [data-slot="trigger"] { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-2); + padding: var(--space-2) var(--space-3); + border: none; + border-radius: var(--border-radius-sm); + background-color: transparent; + color: var(--color-text); + font-size: var(--font-size-sm); + font-family: var(--font-sans); + cursor: pointer; + transition: all 0.15s ease; + + &:hover { + background-color: var(--color-surface-hover); + } + + span { + flex: 1; + text-align: left; + font-weight: 500; + } + } + + [data-slot="chevron"] { + flex-shrink: 0; + color: var(--color-text-secondary); + } + + [data-slot="dropdown"] { + position: absolute; + top: 100%; + z-index: 1000; + margin-top: var(--space-1); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + min-width: 160px; + + &[data-align="left"] { + left: 0; + } + + &[data-align="right"] { + right: 0; + } + + @media (prefers-color-scheme: dark) { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + } + } + + [data-slot="item"] { + display: block; + width: 100%; + padding: var(--space-2-5) var(--space-3); + border: none; + background: none; + color: var(--color-text); + font-size: var(--font-size-sm); + font-family: var(--font-sans); + text-align: left; + cursor: pointer; + transition: background-color 0.15s ease; + + &:hover { + background-color: var(--color-bg-surface); + } + + &[data-selected="true"] { + background-color: var(--color-accent-alpha); + } + } +} diff --git a/packages/console/app/src/component/dropdown.tsx b/packages/console/app/src/component/dropdown.tsx new file mode 100644 index 00000000000..de99d448151 --- /dev/null +++ b/packages/console/app/src/component/dropdown.tsx @@ -0,0 +1,79 @@ +import { JSX, Show, createEffect, onCleanup } from "solid-js" +import { createStore } from "solid-js/store" +import { IconChevron } from "./icon" +import "./dropdown.css" + +interface DropdownProps { + trigger: JSX.Element | string + children: JSX.Element + open?: boolean + onOpenChange?: (open: boolean) => void + align?: "left" | "right" + class?: string +} + +export function Dropdown(props: DropdownProps) { + const [store, setStore] = createStore({ + isOpen: props.open ?? false, + }) + let dropdownRef: HTMLDivElement | undefined + + createEffect(() => { + if (props.open !== undefined) { + setStore("isOpen", props.open) + } + }) + + createEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef && !dropdownRef.contains(event.target as Node)) { + setStore("isOpen", false) + props.onOpenChange?.(false) + } + } + + document.addEventListener("click", handleClickOutside) + onCleanup(() => document.removeEventListener("click", handleClickOutside)) + }) + + const toggle = () => { + const newValue = !store.isOpen + setStore("isOpen", newValue) + props.onOpenChange?.(newValue) + } + + return ( +
+ + + +
+ {props.children} +
+
+
+ ) +} + +interface DropdownItemProps { + children: JSX.Element + selected?: boolean + onClick?: () => void + type?: "button" | "submit" | "reset" +} + +export function DropdownItem(props: DropdownItemProps) { + return ( + + ) +} diff --git a/packages/console/app/src/component/email-signup.tsx b/packages/console/app/src/component/email-signup.tsx new file mode 100644 index 00000000000..65f81b5fc6d --- /dev/null +++ b/packages/console/app/src/component/email-signup.tsx @@ -0,0 +1,48 @@ +import { action, useSubmission } from "@solidjs/router" +import dock from "../asset/lander/dock.png" +import { Resource } from "@opencode-ai/console-resource" +import { Show } from "solid-js" + +const emailSignup = action(async (formData: FormData) => { + "use server" + const emailAddress = formData.get("email")! + const listId = "8b9bb82c-9d5f-11f0-975f-0df6fd1e4945" + const response = await fetch(`https://api.emailoctopus.com/lists/${listId}/contacts`, { + method: "PUT", + headers: { + Authorization: `Bearer ${Resource.EMAILOCTOPUS_API_KEY.value}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email_address: emailAddress, + }), + }) + console.log(response) + return true +}) + +export function EmailSignup() { + const submission = useSubmission(emailSignup) + return ( +
+
+

Be the first to know when we release new products

+

Join the waitlist for early access.

+
+
+ + +
+ +
+ Almost done, check your inbox and confirm your email address +
+
+ +
{submission.error}
+
+
+ ) +} diff --git a/packages/console/app/src/component/faq.tsx b/packages/console/app/src/component/faq.tsx new file mode 100644 index 00000000000..753a0dce4de --- /dev/null +++ b/packages/console/app/src/component/faq.tsx @@ -0,0 +1,33 @@ +import { Collapsible } from "@kobalte/core/collapsible" +import { ParentProps } from "solid-js" + +export function Faq(props: ParentProps & { question: string }) { + return ( + + + + + + + + +
{props.question}
+
+ {props.children} +
+ ) +} diff --git a/packages/console/app/src/component/footer.tsx b/packages/console/app/src/component/footer.tsx new file mode 100644 index 00000000000..27f8ddd65f1 --- /dev/null +++ b/packages/console/app/src/component/footer.tsx @@ -0,0 +1,38 @@ +import { createAsync } from "@solidjs/router" +import { createMemo } from "solid-js" +import { github } from "~/lib/github" +import { config } from "~/config" + +export function Footer() { + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()!.stars!) + : config.github.starsFormatted.compact, + ) + + return ( + + ) +} diff --git a/packages/console/app/src/component/header-context-menu.css b/packages/console/app/src/component/header-context-menu.css new file mode 100644 index 00000000000..34177457d11 --- /dev/null +++ b/packages/console/app/src/component/header-context-menu.css @@ -0,0 +1,63 @@ +.context-menu { + position: fixed; + z-index: 1000; + min-width: 160px; + border-radius: 8px; + background-color: var(--color-background); + box-shadow: + 0 0 0 1px rgba(19, 16, 16, 0.08), + 0 6px 8px -4px rgba(19, 16, 16, 0.12), + 0 4px 3px -2px rgba(19, 16, 16, 0.12), + 0 1px 2px -1px rgba(19, 16, 16, 0.12); + padding: 6px; + + @media (prefers-color-scheme: dark) { + box-shadow: 0 0 0 1px rgba(247, 237, 237, 0.1); + } +} + +.context-menu-item { + display: flex; + gap: 12px; + width: 100%; + padding: 8px 16px 8px 8px; + font-weight: 500; + cursor: pointer; + background: none; + border: none; + align-items: center; + color: var(--color-text); + font-size: var(--font-size-sm); + text-align: left; + border-radius: 2px; + transition: background-color 0.2s ease; + + [data-slot="copy dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="copy light"] { + display: none; + } + [data-slot="copy dark"] { + display: block; + } + } + + &:hover { + background-color: var(--color-background-weak-hover); + color: var(--color-text-strong); + } + + img { + width: 22px; + height: 26px; + } +} + +.context-menu-divider { + border: none; + border-top: 1px solid var(--color-border); + margin: var(--space-1) 0; +} diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx new file mode 100644 index 00000000000..7bfcc782508 --- /dev/null +++ b/packages/console/app/src/component/header.tsx @@ -0,0 +1,279 @@ +import logoLight from "../asset/logo-ornate-light.svg" +import logoDark from "../asset/logo-ornate-dark.svg" +import copyLogoLight from "../asset/lander/logo-light.svg" +import copyLogoDark from "../asset/lander/logo-dark.svg" +import copyWordmarkLight from "../asset/lander/wordmark-light.svg" +import copyWordmarkDark from "../asset/lander/wordmark-dark.svg" +import copyBrandAssetsLight from "../asset/lander/brand-assets-light.svg" +import copyBrandAssetsDark from "../asset/lander/brand-assets-dark.svg" + +// SVG files for copying (separate from button icons) +// Replace these with your actual SVG files for copying +import copyLogoSvgLight from "../asset/lander/opencode-logo-light.svg" +import copyLogoSvgDark from "../asset/lander/opencode-logo-dark.svg" +import copyWordmarkSvgLight from "../asset/lander/opencode-wordmark-light.svg" +import copyWordmarkSvgDark from "../asset/lander/opencode-wordmark-dark.svg" +import { A, createAsync, useNavigate } from "@solidjs/router" +import { createMemo, Match, Show, Switch } from "solid-js" +import { createStore } from "solid-js/store" +import { github } from "~/lib/github" +import { createEffect, onCleanup } from "solid-js" +import { config } from "~/config" +import "./header-context-menu.css" + +const isDarkMode = () => window.matchMedia("(prefers-color-scheme: dark)").matches + +const fetchSvgContent = async (svgPath: string): Promise => { + try { + const response = await fetch(svgPath) + const svgText = await response.text() + return svgText + } catch (err) { + console.error("Failed to fetch SVG content:", err) + throw err + } +} + +export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) { + const navigate = useNavigate() + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()?.stars!) + : config.github.starsFormatted.compact, + ) + + const [store, setStore] = createStore({ + mobileMenuOpen: false, + contextMenuOpen: false, + contextMenuPosition: { x: 0, y: 0 }, + }) + + createEffect(() => { + const handleClickOutside = () => { + setStore("contextMenuOpen", false) + } + + const handleContextMenu = (event: MouseEvent) => { + event.preventDefault() + setStore("contextMenuOpen", false) + } + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + setStore("contextMenuOpen", false) + } + } + + if (store.contextMenuOpen) { + document.addEventListener("click", handleClickOutside) + document.addEventListener("contextmenu", handleContextMenu) + document.addEventListener("keydown", handleKeyDown) + onCleanup(() => { + document.removeEventListener("click", handleClickOutside) + document.removeEventListener("contextmenu", handleContextMenu) + document.removeEventListener("keydown", handleKeyDown) + }) + } + }) + + const handleLogoContextMenu = (event: MouseEvent) => { + event.preventDefault() + const logoElement = (event.currentTarget as HTMLElement).querySelector("a") + if (logoElement) { + const rect = logoElement.getBoundingClientRect() + setStore("contextMenuPosition", { + x: rect.left - 16, + y: rect.bottom + 8, + }) + } + setStore("contextMenuOpen", true) + } + + const copyWordmarkToClipboard = async () => { + try { + const isDark = isDarkMode() + const wordmarkSvgPath = isDark ? copyWordmarkSvgDark : copyWordmarkSvgLight + const wordmarkSvg = await fetchSvgContent(wordmarkSvgPath) + await navigator.clipboard.writeText(wordmarkSvg) + } catch (err) { + console.error("Failed to copy wordmark to clipboard:", err) + } + } + + const copyLogoToClipboard = async () => { + try { + const isDark = isDarkMode() + const logoSvgPath = isDark ? copyLogoSvgDark : copyLogoSvgLight + const logoSvg = await fetchSvgContent(logoSvgPath) + await navigator.clipboard.writeText(logoSvg) + } catch (err) { + console.error("Failed to copy logo to clipboard:", err) + } + } + + return ( +
+ + + +
+ + + +
+
+ + +
+ ) +} diff --git a/packages/console/app/src/component/icon.tsx b/packages/console/app/src/component/icon.tsx new file mode 100644 index 00000000000..1225aeb10c8 --- /dev/null +++ b/packages/console/app/src/component/icon.tsx @@ -0,0 +1,257 @@ +import { JSX } from "solid-js" + +export function IconLogo(props: JSX.SvgSVGAttributes) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export function IconCopy(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconCheck(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconCreditCard(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconStripe(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconChevron(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconWorkspaceLogo(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconOpenAI(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconAnthropic(props: JSX.SvgSVGAttributes) { + return ( + + + + + ) +} + +export function IconXai(props: JSX.SvgSVGAttributes) { + return ( + + + + + ) +} + +export function IconAlibaba(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconMoonshotAI(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconZai(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconMiniMax(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconGemini(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconStealth(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconChevronLeft(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconChevronRight(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +export function IconBreakdown(props: JSX.SvgSVGAttributes) { + return ( + + + + + + + ) +} diff --git a/packages/console/app/src/component/legal.tsx b/packages/console/app/src/component/legal.tsx new file mode 100644 index 00000000000..e971a31e171 --- /dev/null +++ b/packages/console/app/src/component/legal.tsx @@ -0,0 +1,20 @@ +import { A } from "@solidjs/router" + +export function Legal() { + return ( +
+ + ©{new Date().getFullYear()} Anomaly + + + Brand + + + Privacy + + + Terms + +
+ ) +} diff --git a/packages/console/app/src/component/modal.css b/packages/console/app/src/component/modal.css new file mode 100644 index 00000000000..1f47f395de8 --- /dev/null +++ b/packages/console/app/src/component/modal.css @@ -0,0 +1,66 @@ +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(20px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +[data-component="modal"][data-slot="overlay"] { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.5); + animation: fadeIn 0.2s ease; + + @media (prefers-color-scheme: dark) { + background-color: rgba(0, 0, 0, 0.7); + } + + [data-slot="content"] { + background-color: var(--color-bg); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-md); + padding: var(--space-6); + min-width: 400px; + max-width: 90vw; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2); + animation: slideUp 0.2s ease; + + @media (max-width: 30rem) { + min-width: 300px; + padding: var(--space-4); + } + + @media (prefers-color-scheme: dark) { + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); + } + } + + [data-slot="title"] { + margin: 0 0 var(--space-4) 0; + font-size: var(--font-size-lg); + font-weight: 600; + color: var(--color-text); + } +} diff --git a/packages/console/app/src/component/modal.tsx b/packages/console/app/src/component/modal.tsx new file mode 100644 index 00000000000..d6dc8a3de53 --- /dev/null +++ b/packages/console/app/src/component/modal.tsx @@ -0,0 +1,24 @@ +import { JSX, Show } from "solid-js" +import "./modal.css" + +interface ModalProps { + open: boolean + onClose: () => void + title?: string + children: JSX.Element +} + +export function Modal(props: ModalProps) { + return ( + +
+
e.stopPropagation()}> + +

{props.title}

+
+ {props.children} +
+
+
+ ) +} diff --git a/packages/console/app/src/component/spotlight.css b/packages/console/app/src/component/spotlight.css new file mode 100644 index 00000000000..4b311c3d021 --- /dev/null +++ b/packages/console/app/src/component/spotlight.css @@ -0,0 +1,15 @@ +.spotlight-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 50dvh; + pointer-events: none; + overflow: hidden; +} + +.spotlight-container canvas { + display: block; + width: 100%; + height: 100%; +} diff --git a/packages/console/app/src/component/spotlight.tsx b/packages/console/app/src/component/spotlight.tsx new file mode 100644 index 00000000000..70430699055 --- /dev/null +++ b/packages/console/app/src/component/spotlight.tsx @@ -0,0 +1,820 @@ +import { createSignal, createEffect, onMount, onCleanup, Accessor } from "solid-js" +import "./spotlight.css" + +export interface ParticlesConfig { + enabled: boolean + amount: number + size: [number, number] + speed: number + opacity: number + drift: number +} + +export interface SpotlightConfig { + placement: [number, number] + color: string + speed: number + spread: number + length: number + width: number + pulsating: false | [number, number] + distance: number + saturation: number + noiseAmount: number + distortion: number + opacity: number + particles: ParticlesConfig +} + +export const defaultConfig: SpotlightConfig = { + placement: [0.5, -0.15], + color: "#ffffff", + speed: 0.8, + spread: 0.5, + length: 4.0, + width: 0.15, + pulsating: [0.95, 1.1], + distance: 3.5, + saturation: 0.35, + noiseAmount: 0.15, + distortion: 0.05, + opacity: 0.325, + particles: { + enabled: true, + amount: 70, + size: [1.25, 1.5], + speed: 0.75, + opacity: 0.9, + drift: 1.5, + }, +} + +export interface SpotlightAnimationState { + time: number + intensity: number + pulseValue: number +} + +interface SpotlightProps { + config: Accessor + class?: string + onAnimationFrame?: (state: SpotlightAnimationState) => void +} + +const hexToRgb = (hex: string): [number, number, number] => { + const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) + return m ? [parseInt(m[1], 16) / 255, parseInt(m[2], 16) / 255, parseInt(m[3], 16) / 255] : [1, 1, 1] +} + +const getAnchorAndDir = ( + placement: [number, number], + w: number, + h: number, +): { anchor: [number, number]; dir: [number, number] } => { + const [px, py] = placement + const outside = 0.2 + + let anchorX = px * w + let anchorY = py * h + let dirX = 0 + let dirY = 0 + + const centerX = 0.5 + const centerY = 0.5 + + if (py <= 0.25) { + anchorY = -outside * h + py * h + dirY = 1 + dirX = (centerX - px) * 0.5 + } else if (py >= 0.75) { + anchorY = (1 + outside) * h - (1 - py) * h + dirY = -1 + dirX = (centerX - px) * 0.5 + } else if (px <= 0.25) { + anchorX = -outside * w + px * w + dirX = 1 + dirY = (centerY - py) * 0.5 + } else if (px >= 0.75) { + anchorX = (1 + outside) * w - (1 - px) * w + dirX = -1 + dirY = (centerY - py) * 0.5 + } else { + dirY = 1 + } + + const len = Math.sqrt(dirX * dirX + dirY * dirY) + if (len > 0) { + dirX /= len + dirY /= len + } + + return { anchor: [anchorX, anchorY], dir: [dirX, dirY] } +} + +interface UniformData { + iTime: number + iResolution: [number, number] + lightPos: [number, number] + lightDir: [number, number] + color: [number, number, number] + speed: number + lightSpread: number + lightLength: number + sourceWidth: number + pulsating: number + pulsatingMin: number + pulsatingMax: number + fadeDistance: number + saturation: number + noiseAmount: number + distortion: number + particlesEnabled: number + particleAmount: number + particleSizeMin: number + particleSizeMax: number + particleSpeed: number + particleOpacity: number + particleDrift: number +} + +const WGSL_SHADER = ` + struct Uniforms { + iTime: f32, + _pad0: f32, + iResolution: vec2, + lightPos: vec2, + lightDir: vec2, + color: vec3, + speed: f32, + lightSpread: f32, + lightLength: f32, + sourceWidth: f32, + pulsating: f32, + pulsatingMin: f32, + pulsatingMax: f32, + fadeDistance: f32, + saturation: f32, + noiseAmount: f32, + distortion: f32, + particlesEnabled: f32, + particleAmount: f32, + particleSizeMin: f32, + particleSizeMax: f32, + particleSpeed: f32, + particleOpacity: f32, + particleDrift: f32, + _pad1: f32, + _pad2: f32, + }; + + @group(0) @binding(0) var uniforms: Uniforms; + + struct VertexOutput { + @builtin(position) position: vec4, + @location(0) vUv: vec2, + }; + + @vertex + fn vertexMain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput { + var positions = array, 3>( + vec2(-1.0, -1.0), + vec2(3.0, -1.0), + vec2(-1.0, 3.0) + ); + + var output: VertexOutput; + let pos = positions[vertexIndex]; + output.position = vec4(pos, 0.0, 1.0); + output.vUv = pos * 0.5 + 0.5; + return output; + } + + fn hash(p: vec2) -> f32 { + let p3 = fract(p.xyx * 0.1031); + return fract((p3.x + p3.y) * p3.z + dot(p3, p3.yzx + 33.33)); + } + + fn hash2(p: vec2) -> vec2 { + let n = sin(dot(p, vec2(41.0, 289.0))); + return fract(vec2(n * 262144.0, n * 32768.0)); + } + + fn fastNoise(st: vec2) -> f32 { + return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453); + } + + fn lightStrengthCombined(lightSource: vec2, lightRefDirection: vec2, coord: vec2) -> f32 { + let sourceToCoord = coord - lightSource; + let distSq = dot(sourceToCoord, sourceToCoord); + let distance = sqrt(distSq); + + let baseSize = min(uniforms.iResolution.x, uniforms.iResolution.y); + let maxDistance = max(baseSize * uniforms.lightLength, 0.001); + if (distance > maxDistance) { + return 0.0; + } + + let invDist = 1.0 / max(distance, 0.001); + let dirNorm = sourceToCoord * invDist; + let cosAngle = dot(dirNorm, lightRefDirection); + + if (cosAngle < 0.0) { + return 0.0; + } + + let side = dot(dirNorm, vec2(-lightRefDirection.y, lightRefDirection.x)); + let time = uniforms.iTime; + let speed = uniforms.speed; + + let asymNoise = fastNoise(vec2(side * 6.0 + time * 0.12, distance * 0.004 + cosAngle * 2.0)); + let asymShift = (asymNoise - 0.5) * uniforms.distortion * 0.6; + + let distortPhase = time * 1.4 + distance * 0.006 + cosAngle * 4.5 + side * 1.7; + let distortedAngle = cosAngle + uniforms.distortion * sin(distortPhase) * 0.22 + asymShift; + + let flickerSeed = cosAngle * 9.0 + side * 4.0 + time * speed * 0.35; + let flicker = 0.86 + fastNoise(vec2(flickerSeed, distance * 0.01)) * 0.28; + + let asymSpread = max(uniforms.lightSpread * (0.9 + (asymNoise - 0.5) * 0.25), 0.001); + let spreadFactor = pow(max(distortedAngle, 0.0), 1.0 / asymSpread); + let lengthFalloff = clamp(1.0 - distance / maxDistance, 0.0, 1.0); + + let fadeMaxDist = max(baseSize * uniforms.fadeDistance, 0.001); + let fadeFalloff = clamp((fadeMaxDist - distance) / fadeMaxDist, 0.0, 1.0); + + var pulse: f32 = 1.0; + if (uniforms.pulsating > 0.5) { + let pulseCenter = (uniforms.pulsatingMin + uniforms.pulsatingMax) * 0.5; + let pulseAmplitude = (uniforms.pulsatingMax - uniforms.pulsatingMin) * 0.5; + pulse = pulseCenter + pulseAmplitude * sin(time * speed * 3.0); + } + + let timeSpeed = time * speed; + let wave = 0.5 + + 0.25 * sin(cosAngle * 28.0 + side * 8.0 + timeSpeed * 1.2) + + 0.18 * cos(cosAngle * 22.0 - timeSpeed * 0.95 + side * 6.0) + + 0.12 * sin(cosAngle * 35.0 + timeSpeed * 1.6 + asymNoise * 3.0); + let minStrength = 0.14 + asymNoise * 0.06; + let baseStrength = max(clamp(wave * (0.85 + asymNoise * 0.3), 0.0, 1.0), minStrength); + + let lightStrength = baseStrength * lengthFalloff * fadeFalloff * spreadFactor * pulse * flicker; + let ambientLight = (0.06 + asymNoise * 0.04) * lengthFalloff * fadeFalloff * spreadFactor; + + return max(lightStrength, ambientLight); + } + + fn particle(coord: vec2, particlePos: vec2, size: f32) -> f32 { + let delta = coord - particlePos; + let distSq = dot(delta, delta); + let sizeSq = size * size; + + if (distSq > sizeSq * 9.0) { + return 0.0; + } + + let d = sqrt(distSq); + let core = smoothstep(size, size * 0.35, d); + let glow = smoothstep(size * 3.0, 0.0, d) * 0.55; + return core + glow; + } + + fn renderParticles(coord: vec2, lightSource: vec2, lightDir: vec2) -> f32 { + if (uniforms.particlesEnabled < 0.5 || uniforms.particleAmount < 1.0) { + return 0.0; + } + + var particleSum: f32 = 0.0; + let particleCount = i32(uniforms.particleAmount); + let time = uniforms.iTime * uniforms.particleSpeed; + let perpDir = vec2(-lightDir.y, lightDir.x); + let baseSize = min(uniforms.iResolution.x, uniforms.iResolution.y); + let maxDist = max(baseSize * uniforms.lightLength, 1.0); + let spreadScale = uniforms.lightSpread * baseSize * 0.65; + let coneHalfWidth = uniforms.lightSpread * baseSize * 0.55; + + for (var i: i32 = 0; i < particleCount; i = i + 1) { + let fi = f32(i); + let seed = vec2(fi * 127.1, fi * 311.7); + let rnd = hash2(seed); + + let lifeDuration = 2.0 + hash(seed + vec2(19.0, 73.0)) * 3.0; + let lifeOffset = hash(seed + vec2(91.0, 37.0)) * lifeDuration; + let lifeProgress = fract((time + lifeOffset) / lifeDuration); + + let fadeIn = smoothstep(0.0, 0.2, lifeProgress); + let fadeOut = 1.0 - smoothstep(0.8, 1.0, lifeProgress); + let lifeFade = fadeIn * fadeOut; + if (lifeFade < 0.01) { + continue; + } + + let alongLight = rnd.x * maxDist * 0.8; + let perpOffset = (rnd.y - 0.5) * spreadScale; + + let floatPhase = rnd.y * 6.28318 + fi * 0.37; + let floatSpeed = 0.35 + rnd.x * 0.9; + let drift = vec2( + sin(time * floatSpeed + floatPhase), + cos(time * floatSpeed * 0.85 + floatPhase * 1.3) + ) * uniforms.particleDrift * baseSize * 0.08; + + let wobble = vec2( + sin(time * 1.4 + floatPhase * 2.1), + cos(time * 1.1 + floatPhase * 1.6) + ) * uniforms.particleDrift * baseSize * 0.03; + + let flowOffset = (rnd.x - 0.5) * baseSize * 0.12 + fract(time * 0.06 + rnd.y) * baseSize * 0.1; + + let basePos = lightSource + lightDir * (alongLight + flowOffset) + perpDir * perpOffset + drift + wobble; + + let toParticle = basePos - lightSource; + let projLen = dot(toParticle, lightDir); + if (projLen < 0.0 || projLen > maxDist) { + continue; + } + + let sideDist = abs(dot(toParticle, perpDir)); + if (sideDist > coneHalfWidth) { + continue; + } + + let size = mix(uniforms.particleSizeMin, uniforms.particleSizeMax, rnd.x); + let twinkle = 0.7 + 0.3 * sin(time * (1.5 + rnd.y * 2.0) + floatPhase); + let distFade = 1.0 - smoothstep(maxDist * 0.2, maxDist * 0.95, projLen); + if (distFade < 0.01) { + continue; + } + + let p = particle(coord, basePos, size); + if (p > 0.0) { + particleSum = particleSum + p * lifeFade * twinkle * distFade * uniforms.particleOpacity; + if (particleSum >= 1.0) { + break; + } + } + } + + return min(particleSum, 1.0); + } + + @fragment + fn fragmentMain(@builtin(position) fragCoord: vec4, @location(0) vUv: vec2) -> @location(0) vec4 { + let coord = vec2(fragCoord.x, fragCoord.y); + + let normalizedX = (coord.x / uniforms.iResolution.x) - 0.5; + let widthOffset = -normalizedX * uniforms.sourceWidth * uniforms.iResolution.x; + + let perpDir = vec2(-uniforms.lightDir.y, uniforms.lightDir.x); + let adjustedLightPos = uniforms.lightPos + perpDir * widthOffset; + + let lightValue = lightStrengthCombined(adjustedLightPos, uniforms.lightDir, coord); + + if (lightValue < 0.001) { + let particles = renderParticles(coord, adjustedLightPos, uniforms.lightDir); + if (particles < 0.001) { + return vec4(0.0, 0.0, 0.0, 0.0); + } + let particleBrightness = particles * 1.8; + return vec4(uniforms.color * particleBrightness, particles * 0.9); + } + + var fragColor = vec4(lightValue, lightValue, lightValue, lightValue); + + if (uniforms.noiseAmount > 0.01) { + let n = fastNoise(coord * 0.5 + uniforms.iTime * 0.5); + let grain = mix(1.0, n, uniforms.noiseAmount * 0.5); + fragColor = vec4(fragColor.rgb * grain, fragColor.a); + } + + let brightness = 1.0 - (coord.y / uniforms.iResolution.y); + fragColor = vec4( + fragColor.x * (0.15 + brightness * 0.85), + fragColor.y * (0.35 + brightness * 0.65), + fragColor.z * (0.55 + brightness * 0.45), + fragColor.a + ); + + if (abs(uniforms.saturation - 1.0) > 0.01) { + let gray = dot(fragColor.rgb, vec3(0.299, 0.587, 0.114)); + fragColor = vec4(mix(vec3(gray), fragColor.rgb, uniforms.saturation), fragColor.a); + } + + fragColor = vec4(fragColor.rgb * uniforms.color, fragColor.a); + + let particles = renderParticles(coord, adjustedLightPos, uniforms.lightDir); + if (particles > 0.001) { + let particleBrightness = particles * 1.8; + fragColor = vec4(fragColor.rgb + uniforms.color * particleBrightness, max(fragColor.a, particles * 0.9)); + } + + return fragColor; + } +` + +const UNIFORM_BUFFER_SIZE = 144 + +function updateUniformBuffer(buffer: Float32Array, data: UniformData): void { + buffer[0] = data.iTime + buffer[2] = data.iResolution[0] + buffer[3] = data.iResolution[1] + buffer[4] = data.lightPos[0] + buffer[5] = data.lightPos[1] + buffer[6] = data.lightDir[0] + buffer[7] = data.lightDir[1] + buffer[8] = data.color[0] + buffer[9] = data.color[1] + buffer[10] = data.color[2] + buffer[11] = data.speed + buffer[12] = data.lightSpread + buffer[13] = data.lightLength + buffer[14] = data.sourceWidth + buffer[15] = data.pulsating + buffer[16] = data.pulsatingMin + buffer[17] = data.pulsatingMax + buffer[18] = data.fadeDistance + buffer[19] = data.saturation + buffer[20] = data.noiseAmount + buffer[21] = data.distortion + buffer[22] = data.particlesEnabled + buffer[23] = data.particleAmount + buffer[24] = data.particleSizeMin + buffer[25] = data.particleSizeMax + buffer[26] = data.particleSpeed + buffer[27] = data.particleOpacity + buffer[28] = data.particleDrift +} + +export default function Spotlight(props: SpotlightProps) { + let containerRef: HTMLDivElement | undefined + let canvasRef: HTMLCanvasElement | null = null + let deviceRef: GPUDevice | null = null + let contextRef: GPUCanvasContext | null = null + let pipelineRef: GPURenderPipeline | null = null + let uniformBufferRef: GPUBuffer | null = null + let bindGroupRef: GPUBindGroup | null = null + let animationIdRef: number | null = null + let cleanupFunctionRef: (() => void) | null = null + let uniformDataRef: UniformData | null = null + let uniformArrayRef: Float32Array | null = null + let configRef: SpotlightConfig = props.config() + let frameCount = 0 + + const [isVisible, setIsVisible] = createSignal(false) + + createEffect(() => { + configRef = props.config() + }) + + onMount(() => { + if (!containerRef) return + + const observer = new IntersectionObserver( + (entries) => { + const entry = entries[0] + setIsVisible(entry.isIntersecting) + }, + { threshold: 0.1 }, + ) + + observer.observe(containerRef) + + onCleanup(() => { + observer.disconnect() + }) + }) + + createEffect(() => { + const visible = isVisible() + const config = props.config() + if (!visible || !containerRef) { + return + } + + if (cleanupFunctionRef) { + cleanupFunctionRef() + cleanupFunctionRef = null + } + + const initializeWebGPU = async () => { + if (!containerRef) { + return + } + + await new Promise((resolve) => setTimeout(resolve, 10)) + + if (!containerRef) { + return + } + + if (!navigator.gpu) { + console.warn("WebGPU is not supported in this browser") + return + } + + const adapter = await navigator.gpu.requestAdapter({ + powerPreference: "high-performance", + }) + if (!adapter) { + console.warn("Failed to get WebGPU adapter") + return + } + + const device = await adapter.requestDevice() + deviceRef = device + + const canvas = document.createElement("canvas") + canvas.style.width = "100%" + canvas.style.height = "100%" + canvasRef = canvas + + while (containerRef.firstChild) { + containerRef.removeChild(containerRef.firstChild) + } + containerRef.appendChild(canvas) + + const context = canvas.getContext("webgpu") + if (!context) { + console.warn("Failed to get WebGPU context") + return + } + contextRef = context + + const presentationFormat = navigator.gpu.getPreferredCanvasFormat() + context.configure({ + device, + format: presentationFormat, + alphaMode: "premultiplied", + }) + + const shaderModule = device.createShaderModule({ + code: WGSL_SHADER, + }) + + const uniformBuffer = device.createBuffer({ + size: UNIFORM_BUFFER_SIZE, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }) + uniformBufferRef = uniformBuffer + + const bindGroupLayout = device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, + buffer: { type: "uniform" }, + }, + ], + }) + + const bindGroup = device.createBindGroup({ + layout: bindGroupLayout, + entries: [ + { + binding: 0, + resource: { buffer: uniformBuffer }, + }, + ], + }) + bindGroupRef = bindGroup + + const pipelineLayout = device.createPipelineLayout({ + bindGroupLayouts: [bindGroupLayout], + }) + + const pipeline = device.createRenderPipeline({ + layout: pipelineLayout, + vertex: { + module: shaderModule, + entryPoint: "vertexMain", + }, + fragment: { + module: shaderModule, + entryPoint: "fragmentMain", + targets: [ + { + format: presentationFormat, + blend: { + color: { + srcFactor: "src-alpha", + dstFactor: "one-minus-src-alpha", + operation: "add", + }, + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add", + }, + }, + }, + ], + }, + primitive: { + topology: "triangle-list", + }, + }) + pipelineRef = pipeline + + const { clientWidth: wCSS, clientHeight: hCSS } = containerRef + const dpr = Math.min(window.devicePixelRatio, 2) + const w = wCSS * dpr + const h = hCSS * dpr + const { anchor, dir } = getAnchorAndDir(config.placement, w, h) + + uniformDataRef = { + iTime: 0, + iResolution: [w, h], + lightPos: anchor, + lightDir: dir, + color: hexToRgb(config.color), + speed: config.speed, + lightSpread: config.spread, + lightLength: config.length, + sourceWidth: config.width, + pulsating: config.pulsating !== false ? 1.0 : 0.0, + pulsatingMin: config.pulsating !== false ? config.pulsating[0] : 1.0, + pulsatingMax: config.pulsating !== false ? config.pulsating[1] : 1.0, + fadeDistance: config.distance, + saturation: config.saturation, + noiseAmount: config.noiseAmount, + distortion: config.distortion, + particlesEnabled: config.particles.enabled ? 1.0 : 0.0, + particleAmount: config.particles.amount, + particleSizeMin: config.particles.size[0], + particleSizeMax: config.particles.size[1], + particleSpeed: config.particles.speed, + particleOpacity: config.particles.opacity, + particleDrift: config.particles.drift, + } + + const updatePlacement = () => { + if (!containerRef || !canvasRef || !uniformDataRef) { + return + } + + const dpr = Math.min(window.devicePixelRatio, 2) + const { clientWidth: wCSS, clientHeight: hCSS } = containerRef + const w = Math.floor(wCSS * dpr) + const h = Math.floor(hCSS * dpr) + + canvasRef.width = w + canvasRef.height = h + + uniformDataRef.iResolution = [w, h] + + const { anchor, dir } = getAnchorAndDir(configRef.placement, w, h) + uniformDataRef.lightPos = anchor + uniformDataRef.lightDir = dir + } + + const loop = (t: number) => { + if (!deviceRef || !contextRef || !pipelineRef || !uniformBufferRef || !bindGroupRef || !uniformDataRef) { + return + } + + const timeSeconds = t * 0.001 + uniformDataRef.iTime = timeSeconds + frameCount++ + + if (props.onAnimationFrame && frameCount % 2 === 0) { + const pulsatingMin = configRef.pulsating !== false ? configRef.pulsating[0] : 1.0 + const pulsatingMax = configRef.pulsating !== false ? configRef.pulsating[1] : 1.0 + const pulseCenter = (pulsatingMin + pulsatingMax) * 0.5 + const pulseAmplitude = (pulsatingMax - pulsatingMin) * 0.5 + const pulseValue = + configRef.pulsating !== false + ? pulseCenter + pulseAmplitude * Math.sin(timeSeconds * configRef.speed * 3.0) + : 1.0 + + const baseIntensity1 = 0.45 + 0.15 * Math.sin(timeSeconds * configRef.speed * 1.5) + const baseIntensity2 = 0.3 + 0.2 * Math.cos(timeSeconds * configRef.speed * 1.1) + const intensity = Math.max((baseIntensity1 + baseIntensity2) * pulseValue, 0.55) + + props.onAnimationFrame({ + time: timeSeconds, + intensity, + pulseValue: Math.max(pulseValue, 0.9), + }) + } + + try { + if (!uniformArrayRef) { + uniformArrayRef = new Float32Array(36) + } + updateUniformBuffer(uniformArrayRef, uniformDataRef) + deviceRef.queue.writeBuffer(uniformBufferRef, 0, uniformArrayRef.buffer) + + const commandEncoder = deviceRef.createCommandEncoder() + + const textureView = contextRef.getCurrentTexture().createView() + + const renderPass = commandEncoder.beginRenderPass({ + colorAttachments: [ + { + view: textureView, + clearValue: { r: 0, g: 0, b: 0, a: 0 }, + loadOp: "clear", + storeOp: "store", + }, + ], + }) + + renderPass.setPipeline(pipelineRef) + renderPass.setBindGroup(0, bindGroupRef) + renderPass.draw(3) + renderPass.end() + + deviceRef.queue.submit([commandEncoder.finish()]) + + animationIdRef = requestAnimationFrame(loop) + } catch (error) { + console.warn("WebGPU rendering error:", error) + return + } + } + + window.addEventListener("resize", updatePlacement) + updatePlacement() + animationIdRef = requestAnimationFrame(loop) + + cleanupFunctionRef = () => { + if (animationIdRef) { + cancelAnimationFrame(animationIdRef) + animationIdRef = null + } + + window.removeEventListener("resize", updatePlacement) + + if (uniformBufferRef) { + uniformBufferRef.destroy() + uniformBufferRef = null + } + + if (deviceRef) { + deviceRef.destroy() + deviceRef = null + } + + if (canvasRef && canvasRef.parentNode) { + canvasRef.parentNode.removeChild(canvasRef) + } + + canvasRef = null + contextRef = null + pipelineRef = null + bindGroupRef = null + uniformDataRef = null + } + } + + initializeWebGPU() + + onCleanup(() => { + if (cleanupFunctionRef) { + cleanupFunctionRef() + cleanupFunctionRef = null + } + }) + }) + + createEffect(() => { + if (!uniformDataRef || !containerRef) { + return + } + + const config = props.config() + + uniformDataRef.color = hexToRgb(config.color) + uniformDataRef.speed = config.speed + uniformDataRef.lightSpread = config.spread + uniformDataRef.lightLength = config.length + uniformDataRef.sourceWidth = config.width + uniformDataRef.pulsating = config.pulsating !== false ? 1.0 : 0.0 + uniformDataRef.pulsatingMin = config.pulsating !== false ? config.pulsating[0] : 1.0 + uniformDataRef.pulsatingMax = config.pulsating !== false ? config.pulsating[1] : 1.0 + uniformDataRef.fadeDistance = config.distance + uniformDataRef.saturation = config.saturation + uniformDataRef.noiseAmount = config.noiseAmount + uniformDataRef.distortion = config.distortion + uniformDataRef.particlesEnabled = config.particles.enabled ? 1.0 : 0.0 + uniformDataRef.particleAmount = config.particles.amount + uniformDataRef.particleSizeMin = config.particles.size[0] + uniformDataRef.particleSizeMax = config.particles.size[1] + uniformDataRef.particleSpeed = config.particles.speed + uniformDataRef.particleOpacity = config.particles.opacity + uniformDataRef.particleDrift = config.particles.drift + + const dpr = Math.min(window.devicePixelRatio, 2) + const { clientWidth: wCSS, clientHeight: hCSS } = containerRef + const { anchor, dir } = getAnchorAndDir(config.placement, wCSS * dpr, hCSS * dpr) + uniformDataRef.lightPos = anchor + uniformDataRef.lightDir = dir + }) + + return ( +
+ ) +} diff --git a/packages/console/app/src/config.ts b/packages/console/app/src/config.ts new file mode 100644 index 00000000000..1d99def1b9a --- /dev/null +++ b/packages/console/app/src/config.ts @@ -0,0 +1,29 @@ +/** + * Application-wide constants and configuration + */ +export const config = { + // Base URL + baseUrl: "https://opencode.ai", + + // GitHub + github: { + repoUrl: "https://github.com/anomalyco/opencode", + starsFormatted: { + compact: "80K", + full: "80,000", + }, + }, + + // Social links + social: { + twitter: "https://x.com/opencode", + discord: "https://discord.gg/opencode", + }, + + // Static stats (used on landing page) + stats: { + contributors: "600", + commits: "7,500", + monthlyUsers: "1.5M", + }, +} as const diff --git a/packages/opencode/src/cli/cmd/opentui/opentui.ts b/packages/console/app/src/context/auth.session.ts similarity index 100% rename from packages/opencode/src/cli/cmd/opentui/opentui.ts rename to packages/console/app/src/context/auth.session.ts diff --git a/packages/console/app/src/context/auth.ts b/packages/console/app/src/context/auth.ts new file mode 100644 index 00000000000..aed07a630f8 --- /dev/null +++ b/packages/console/app/src/context/auth.ts @@ -0,0 +1,116 @@ +import { getRequestEvent } from "solid-js/web" +import { and, Database, eq, inArray, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js" +import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" +import { redirect } from "@solidjs/router" +import { Actor } from "@opencode-ai/console-core/actor.js" + +import { createClient } from "@openauthjs/openauth/client" + +export const AuthClient = createClient({ + clientID: "app", + issuer: import.meta.env.VITE_AUTH_URL, +}) + +import { useSession } from "@solidjs/start/http" +import { Resource } from "@opencode-ai/console-resource" + +export interface AuthSession { + account?: Record< + string, + { + id: string + email: string + } + > + current?: string +} + +export function useAuthSession() { + return useSession({ + password: Resource.ZEN_SESSION_SECRET.value, + name: "auth", + maxAge: 60 * 60 * 24 * 365, + cookie: { + secure: false, + httpOnly: true, + }, + }) +} + +export const getActor = async (workspace?: string): Promise => { + "use server" + const evt = getRequestEvent() + if (!evt) throw new Error("No request event") + if (evt.locals.actor) return evt.locals.actor + evt.locals.actor = (async () => { + const auth = await useAuthSession() + if (!workspace) { + const account = auth.data.account ?? {} + const current = account[auth.data.current ?? ""] + if (current) { + return { + type: "account", + properties: { + email: current.email, + accountID: current.id, + }, + } + } + if (Object.keys(account).length > 0) { + const current = Object.values(account)[0] + await auth.update((val) => ({ + ...val, + current: current.id, + })) + return { + type: "account", + properties: { + email: current.email, + accountID: current.id, + }, + } + } + return { + type: "public", + properties: {}, + } + } + const accounts = Object.keys(auth.data.account ?? {}) + if (accounts.length) { + const user = await Database.use((tx) => + tx + .select() + .from(UserTable) + .where( + and( + eq(UserTable.workspaceID, workspace), + isNull(UserTable.timeDeleted), + inArray(UserTable.accountID, accounts), + ), + ) + .limit(1) + .execute() + .then((x) => x[0]), + ) + if (user) { + await Database.use((tx) => + tx + .update(UserTable) + .set({ timeSeen: sql`now()` }) + .where(and(eq(UserTable.workspaceID, workspace), eq(UserTable.id, user.id))), + ) + return { + type: "user", + properties: { + userID: user.id, + workspaceID: user.workspaceID, + accountID: user.accountID, + role: user.role, + }, + } + } + } + throw redirect("/auth/authorize") + })() + return evt.locals.actor +} diff --git a/packages/console/app/src/context/auth.withActor.ts b/packages/console/app/src/context/auth.withActor.ts new file mode 100644 index 00000000000..ff377cda460 --- /dev/null +++ b/packages/console/app/src/context/auth.withActor.ts @@ -0,0 +1,7 @@ +import { Actor } from "@opencode-ai/console-core/actor.js" +import { getActor } from "./auth" + +export async function withActor(fn: () => T, workspace?: string) { + const actor = await getActor(workspace) + return Actor.provide(actor.type, actor.properties, fn) +} diff --git a/packages/console/app/src/entry-client.tsx b/packages/console/app/src/entry-client.tsx new file mode 100644 index 00000000000..642deacf73c --- /dev/null +++ b/packages/console/app/src/entry-client.tsx @@ -0,0 +1,4 @@ +// @refresh reload +import { mount, StartClient } from "@solidjs/start/client" + +mount(() => , document.getElementById("app")!) diff --git a/packages/console/app/src/entry-server.tsx b/packages/console/app/src/entry-server.tsx new file mode 100644 index 00000000000..deaadc747de --- /dev/null +++ b/packages/console/app/src/entry-server.tsx @@ -0,0 +1,30 @@ +// @refresh reload +import { createHandler, StartServer } from "@solidjs/start/server" + +const criticalCSS = `[data-component="top"]{min-height:80px;display:flex;align-items:center}` + +export default createHandler( + () => ( + ( + + + + + + + + {assets} + + +
{children}
+ {scripts} + + + )} + /> + ), + { + mode: "async", + }, +) diff --git a/packages/console/app/src/global.d.ts b/packages/console/app/src/global.d.ts new file mode 100644 index 00000000000..4c2b0a1700e --- /dev/null +++ b/packages/console/app/src/global.d.ts @@ -0,0 +1,5 @@ +/// + +export declare module "@solidjs/start/server" { + export type APIEvent = { request: Request } +} diff --git a/packages/console/app/src/lib/github.ts b/packages/console/app/src/lib/github.ts new file mode 100644 index 00000000000..ccde5972d37 --- /dev/null +++ b/packages/console/app/src/lib/github.ts @@ -0,0 +1,38 @@ +import { query } from "@solidjs/router" +import { config } from "~/config" + +export const github = query(async () => { + "use server" + const headers = { + "User-Agent": + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", + } + const apiBaseUrl = config.github.repoUrl.replace("https://github.com/", "https://api.github.com/repos/") + try { + const [meta, releases, contributors] = await Promise.all([ + fetch(apiBaseUrl, { headers }).then((res) => res.json()), + fetch(`${apiBaseUrl}/releases`, { headers }).then((res) => res.json()), + fetch(`${apiBaseUrl}/contributors?per_page=1`, { headers }), + ]) + if (!Array.isArray(releases) || releases.length === 0) { + return undefined + } + const [release] = releases + const linkHeader = contributors.headers.get("Link") + const contributorCount = linkHeader + ? Number.parseInt(linkHeader.match(/&page=(\d+)>; rel="last"/)?.at(1) ?? "0") + : 0 + return { + stars: meta.stargazers_count, + release: { + name: release.name, + url: release.html_url, + tag_name: release.tag_name, + }, + contributors: contributorCount, + } + } catch (e) { + console.error(e) + } + return undefined +}, "github") diff --git a/packages/console/app/src/middleware.ts b/packages/console/app/src/middleware.ts new file mode 100644 index 00000000000..620fc25aa41 --- /dev/null +++ b/packages/console/app/src/middleware.ts @@ -0,0 +1,5 @@ +import { createMiddleware } from "@solidjs/start/middleware" + +export default createMiddleware({ + onBeforeResponse() {}, +}) diff --git a/packages/console/app/src/routes/[...404].css b/packages/console/app/src/routes/[...404].css new file mode 100644 index 00000000000..1edbd0a5a70 --- /dev/null +++ b/packages/console/app/src/routes/[...404].css @@ -0,0 +1,130 @@ +[data-page="not-found"] { + --color-text: hsl(224, 10%, 10%); + --color-text-secondary: hsl(224, 7%, 46%); + --color-text-dimmed: hsl(224, 6%, 63%); + --color-text-inverted: hsl(0, 0%, 100%); + + --color-border: hsl(224, 6%, 77%); +} + +[data-page="not-found"] { + @media (prefers-color-scheme: dark) { + --color-text: hsl(0, 0%, 100%); + --color-text-secondary: hsl(224, 6%, 66%); + --color-text-dimmed: hsl(224, 7%, 46%); + --color-text-inverted: hsl(224, 10%, 10%); + + --color-border: hsl(224, 6%, 36%); + } +} + +[data-page="not-found"] { + --padding: 3rem; + --vertical-padding: 1.5rem; + --heading-font-size: 1.375rem; + + @media (max-width: 30rem) { + --padding: 1rem; + --vertical-padding: 0.75rem; + --heading-font-size: 1rem; + } + + font-family: var(--font-mono); + color: var(--color-text); + padding: calc(var(--padding) + 1rem); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + + a { + color: var(--color-text); + text-decoration: underline; + text-underline-offset: var(--space-0-75); + text-decoration-thickness: 1px; + } + + [data-component="content"] { + max-width: 40rem; + width: 100%; + border: 1px solid var(--color-border); + } + + [data-component="top"] { + padding: var(--padding); + display: flex; + flex-direction: column; + align-items: center; + gap: calc(var(--vertical-padding) / 2); + text-align: center; + + [data-slot="logo-link"] { + text-decoration: none; + } + + img { + height: auto; + width: clamp(200px, 85vw, 400px); + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + + [data-slot="title"] { + line-height: 1.25; + font-weight: 500; + text-align: center; + font-size: var(--heading-font-size); + color: var(--color-text); + text-transform: uppercase; + margin: 0; + } + } + + [data-component="actions"] { + border-top: 1px solid var(--color-border); + display: flex; + + [data-slot="action"] { + flex: 1; + text-align: center; + line-height: 1.4; + padding: var(--vertical-padding) 1rem; + text-transform: uppercase; + font-size: 1rem; + + a { + display: block; + width: 100%; + height: 100%; + color: var(--color-text); + text-decoration: underline; + text-underline-offset: var(--space-0-75); + text-decoration-thickness: 1px; + } + } + + [data-slot="action"] + [data-slot="action"] { + border-left: 1px solid var(--color-border); + } + + @media (max-width: 40rem) { + flex-direction: column; + + [data-slot="action"] + [data-slot="action"] { + border-left: none; + border-top: 1px solid var(--color-border); + } + } + } +} diff --git a/packages/console/app/src/routes/[...404].tsx b/packages/console/app/src/routes/[...404].tsx new file mode 100644 index 00000000000..1fd378774b1 --- /dev/null +++ b/packages/console/app/src/routes/[...404].tsx @@ -0,0 +1,38 @@ +import "./[...404].css" +import { Title } from "@solidjs/meta" +import { HttpStatusCode } from "@solidjs/start" +import logoLight from "../asset/logo-ornate-light.svg" +import logoDark from "../asset/logo-ornate-dark.svg" + +export default function NotFound() { + return ( +
+ Not Found | opencode + +
+
+ + opencode logo light + opencode logo dark + +

404 - Page Not Found

+
+ +
+
+ Home +
+
+ Docs +
+
+ GitHub +
+
+ Discord +
+
+
+
+ ) +} diff --git a/packages/console/app/src/routes/api/enterprise.ts b/packages/console/app/src/routes/api/enterprise.ts new file mode 100644 index 00000000000..6776a7b3c73 --- /dev/null +++ b/packages/console/app/src/routes/api/enterprise.ts @@ -0,0 +1,47 @@ +import type { APIEvent } from "@solidjs/start/server" +import { AWS } from "@opencode-ai/console-core/aws.js" + +interface EnterpriseFormData { + name: string + role: string + email: string + message: string +} + +export async function POST(event: APIEvent) { + try { + const body = (await event.request.json()) as EnterpriseFormData + + // Validate required fields + if (!body.name || !body.role || !body.email || !body.message) { + return Response.json({ error: "All fields are required" }, { status: 400 }) + } + + // Validate email format + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + if (!emailRegex.test(body.email)) { + return Response.json({ error: "Invalid email format" }, { status: 400 }) + } + + // Create email content + const emailContent = ` +${body.message}

+--
+${body.name}
+${body.role}
+${body.email}`.trim() + + // Send email using AWS SES + await AWS.sendEmail({ + to: "contact@anoma.ly", + subject: `Enterprise Inquiry from ${body.name}`, + body: emailContent, + replyTo: body.email, + }) + + return Response.json({ success: true, message: "Form submitted successfully" }, { status: 200 }) + } catch (error) { + console.error("Error processing enterprise form:", error) + return Response.json({ error: "Internal server error" }, { status: 500 }) + } +} diff --git a/packages/console/app/src/routes/auth/[...callback].ts b/packages/console/app/src/routes/auth/[...callback].ts new file mode 100644 index 00000000000..36a9c5194d0 --- /dev/null +++ b/packages/console/app/src/routes/auth/[...callback].ts @@ -0,0 +1,41 @@ +import { redirect } from "@solidjs/router" +import type { APIEvent } from "@solidjs/start/server" +import { AuthClient } from "~/context/auth" +import { useAuthSession } from "~/context/auth" + +export async function GET(input: APIEvent) { + const url = new URL(input.request.url) + + try { + const code = url.searchParams.get("code") + if (!code) throw new Error("No code found") + const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`) + if (result.err) throw new Error(result.err.message) + const decoded = AuthClient.decode(result.tokens.access, {} as any) + if (decoded.err) throw new Error(decoded.err.message) + const session = await useAuthSession() + const id = decoded.subject.properties.accountID + await session.update((value) => { + return { + ...value, + account: { + ...value.account, + [id]: { + id, + email: decoded.subject.properties.email, + }, + }, + current: id, + } + }) + return redirect(url.pathname === "/auth/callback" ? "/auth" : url.pathname.replace("/auth/callback", "")) + } catch (e: any) { + return new Response( + JSON.stringify({ + error: e.message, + cause: Object.fromEntries(url.searchParams.entries()), + }), + { status: 500 }, + ) + } +} diff --git a/packages/console/app/src/routes/auth/authorize.ts b/packages/console/app/src/routes/auth/authorize.ts new file mode 100644 index 00000000000..0f0651ae36b --- /dev/null +++ b/packages/console/app/src/routes/auth/authorize.ts @@ -0,0 +1,10 @@ +import type { APIEvent } from "@solidjs/start/server" +import { AuthClient } from "~/context/auth" + +export async function GET(input: APIEvent) { + const url = new URL(input.request.url) + const cont = url.searchParams.get("continue") ?? "" + const callbackUrl = new URL(`./callback${cont}`, input.request.url) + const result = await AuthClient.authorize(callbackUrl.toString(), "code") + return Response.redirect(result.url, 302) +} diff --git a/packages/console/app/src/routes/auth/index.ts b/packages/console/app/src/routes/auth/index.ts new file mode 100644 index 00000000000..5b49db157b8 --- /dev/null +++ b/packages/console/app/src/routes/auth/index.ts @@ -0,0 +1,12 @@ +import { redirect } from "@solidjs/router" +import type { APIEvent } from "@solidjs/start/server" +import { getLastSeenWorkspaceID } from "../workspace/common" + +export async function GET(input: APIEvent) { + try { + const workspaceID = await getLastSeenWorkspaceID() + return redirect(`/workspace/${workspaceID}`) + } catch { + return redirect("/auth/authorize") + } +} diff --git a/packages/console/app/src/routes/auth/logout.ts b/packages/console/app/src/routes/auth/logout.ts new file mode 100644 index 00000000000..9aaac37e224 --- /dev/null +++ b/packages/console/app/src/routes/auth/logout.ts @@ -0,0 +1,17 @@ +import { redirect } from "@solidjs/router" +import { APIEvent } from "@solidjs/start" +import { useAuthSession } from "~/context/auth" + +export async function GET(event: APIEvent) { + const auth = await useAuthSession() + const current = auth.data.current + if (current) + await auth.update((val) => { + delete val.account?.[current] + const first = Object.keys(val.account ?? {})[0] + val.current = first + event!.locals.actor = undefined + return val + }) + return redirect("/zen") +} diff --git a/packages/console/app/src/routes/auth/status.ts b/packages/console/app/src/routes/auth/status.ts new file mode 100644 index 00000000000..215cae698f9 --- /dev/null +++ b/packages/console/app/src/routes/auth/status.ts @@ -0,0 +1,7 @@ +import { APIEvent } from "@solidjs/start" +import { useAuthSession } from "~/context/auth" + +export async function GET(input: APIEvent) { + const session = await useAuthSession() + return Response.json(session.data) +} diff --git a/packages/console/app/src/routes/bench/[id].tsx b/packages/console/app/src/routes/bench/[id].tsx new file mode 100644 index 00000000000..4586eef9bf9 --- /dev/null +++ b/packages/console/app/src/routes/bench/[id].tsx @@ -0,0 +1,365 @@ +import { Title } from "@solidjs/meta" +import { createAsync, query, useParams } from "@solidjs/router" +import { createSignal, For, Show } from "solid-js" +import { Database, desc, eq } from "@opencode-ai/console-core/drizzle/index.js" +import { BenchmarkTable } from "@opencode-ai/console-core/schema/benchmark.sql.js" + +interface TaskSource { + repo: string + from: string + to: string +} + +interface Judge { + score: number + rationale: string + judge: string +} + +interface ScoreDetail { + criterion: string + weight: number + average: number + variance?: number + judges?: Judge[] +} + +interface RunUsage { + input: number + output: number + cost: number +} + +interface Run { + task: string + model: string + agent: string + score: { + final: number + base: number + penalty: number + } + scoreDetails: ScoreDetail[] + usage?: RunUsage + duration?: number +} + +interface Prompt { + commit: string + prompt: string +} + +interface AverageUsage { + input: number + output: number + cost: number +} + +interface Task { + averageScore: number + averageDuration?: number + averageUsage?: AverageUsage + model?: string + agent?: string + summary?: string + runs?: Run[] + task: { + id: string + source: TaskSource + prompts?: Prompt[] + } +} + +interface BenchmarkResult { + averageScore: number + tasks: Task[] +} + +async function getTaskDetail(benchmarkId: string, taskId: string) { + "use server" + const rows = await Database.use((tx) => + tx.select().from(BenchmarkTable).where(eq(BenchmarkTable.id, benchmarkId)).limit(1), + ) + if (!rows[0]) return null + const parsed = JSON.parse(rows[0].result) as BenchmarkResult + const task = parsed.tasks.find((t) => t.task.id === taskId) + return task ?? null +} + +const queryTaskDetail = query(getTaskDetail, "benchmark.task.detail") + +function formatDuration(ms: number): string { + const seconds = Math.floor(ms / 1000) + const minutes = Math.floor(seconds / 60) + const remainingSeconds = seconds % 60 + if (minutes > 0) { + return `${minutes}m ${remainingSeconds}s` + } + return `${remainingSeconds}s` +} + +export default function BenchDetail() { + const params = useParams() + const [benchmarkId, taskId] = (params.id ?? "").split(":") + const task = createAsync(() => queryTaskDetail(benchmarkId, taskId)) + + return ( +
+ Benchmark - {taskId} +
+ Task not found

}> +
+
+ Agent: + {task()?.agent ?? "N/A"} +
+
+ Model: + {task()?.model ?? "N/A"} +
+
+ Task: + {task()!.task.id} +
+
+ + + + 0}> +
+ Prompt: + + {(p) => ( +
+
Commit: {p.commit.slice(0, 7)}
+

{p.prompt}

+
+ )} +
+
+
+ +
+ +
+
+ Average Duration: + {task()?.averageDuration ? formatDuration(task()!.averageDuration!) : "N/A"} +
+
+ Average Score: + {task()?.averageScore?.toFixed(3) ?? "N/A"} +
+
+ Average Cost: + {task()?.averageUsage?.cost ? `$${task()!.averageUsage!.cost.toFixed(4)}` : "N/A"} +
+
+ + +
+ Summary: +

{task()!.summary}

+
+
+ + 0}> +
+ Runs: + + + + + + + + + {(detail) => ( + + )} + + + + + + {(run, index) => ( + + + + + + + {(detail) => ( + + )} + + + )} + + +
Run + Score (Base - Penalty) + CostDuration + {detail.criterion} ({detail.weight}) +
{index() + 1} + {run.score.final.toFixed(3)} ({run.score.base.toFixed(3)} - {run.score.penalty.toFixed(3)}) + + {run.usage?.cost ? `$${run.usage.cost.toFixed(4)}` : "N/A"} + + {run.duration ? formatDuration(run.duration) : "N/A"} + + + {(judge) => ( + + {judge.score === 1 ? "✓" : judge.score === 0 ? "✗" : judge.score} + + )} + +
+ + {(run, index) => ( +
+

Run {index() + 1}

+
+ Score: + {run.score.final.toFixed(3)} (Base: {run.score.base.toFixed(3)} - Penalty:{" "} + {run.score.penalty.toFixed(3)}) +
+ + {(detail) => ( +
+
+ {detail.criterion} (weight: {detail.weight}){" "} + + {(judge) => ( + + {judge.score === 1 ? "✓" : judge.score === 0 ? "✗" : judge.score} + + )} + +
+ 0}> + + {(judge) => { + const [expanded, setExpanded] = createSignal(false) + return ( +
+
setExpanded(!expanded())} + > + {expanded() ? "▼" : "▶"} + + {judge.score === 1 ? "✓" : judge.score === 0 ? "✗" : judge.score} + {" "} + {judge.judge} +
+ +

+ {judge.rationale} +

+
+
+ ) + }} +
+
+
+ )} +
+
+ )} +
+
+
+ + {(() => { + const [jsonExpanded, setJsonExpanded] = createSignal(false) + return ( +
+ + +
{JSON.stringify(task(), null, 2)}
+
+
+ ) + })()} +
+
+
+ ) +} diff --git a/packages/console/app/src/routes/bench/index.tsx b/packages/console/app/src/routes/bench/index.tsx new file mode 100644 index 00000000000..9b8d0b8f24f --- /dev/null +++ b/packages/console/app/src/routes/bench/index.tsx @@ -0,0 +1,86 @@ +import { Title } from "@solidjs/meta" +import { A, createAsync, query } from "@solidjs/router" +import { createMemo, For, Show } from "solid-js" +import { Database, desc } from "@opencode-ai/console-core/drizzle/index.js" +import { BenchmarkTable } from "@opencode-ai/console-core/schema/benchmark.sql.js" + +interface BenchmarkResult { + averageScore: number + tasks: { averageScore: number; task: { id: string } }[] +} + +async function getBenchmarks() { + "use server" + const rows = await Database.use((tx) => + tx.select().from(BenchmarkTable).orderBy(desc(BenchmarkTable.timeCreated)).limit(100), + ) + return rows.map((row) => { + const parsed = JSON.parse(row.result) as BenchmarkResult + const taskScores: Record = {} + for (const t of parsed.tasks) { + taskScores[t.task.id] = t.averageScore + } + return { + id: row.id, + agent: row.agent, + model: row.model, + averageScore: parsed.averageScore, + taskScores, + } + }) +} + +const queryBenchmarks = query(getBenchmarks, "benchmarks.list") + +export default function Bench() { + const benchmarks = createAsync(() => queryBenchmarks()) + + const taskIds = createMemo(() => { + const ids = new Set() + for (const row of benchmarks() ?? []) { + for (const id of Object.keys(row.taskScores)) { + ids.add(id) + } + } + return [...ids].sort() + }) + + return ( +
+ Benchmark +

Benchmarks

+ + + + + + + {(id) => } + + + + + {(row) => ( + + + + + + {(id) => ( + + )} + + + )} + + +
AgentModelScore{id}
{row.agent}{row.model}{row.averageScore.toFixed(3)} + + + {row.taskScores[id]?.toFixed(3)} + + +
+
+ ) +} diff --git a/packages/console/app/src/routes/bench/submission.ts b/packages/console/app/src/routes/bench/submission.ts new file mode 100644 index 00000000000..94639439b11 --- /dev/null +++ b/packages/console/app/src/routes/bench/submission.ts @@ -0,0 +1,29 @@ +import type { APIEvent } from "@solidjs/start/server" +import { Database } from "@opencode-ai/console-core/drizzle/index.js" +import { BenchmarkTable } from "@opencode-ai/console-core/schema/benchmark.sql.js" +import { Identifier } from "@opencode-ai/console-core/identifier.js" + +interface SubmissionBody { + model: string + agent: string + result: string +} + +export async function POST(event: APIEvent) { + const body = (await event.request.json()) as SubmissionBody + + if (!body.model || !body.agent || !body.result) { + return Response.json({ error: "All fields are required" }, { status: 400 }) + } + + await Database.use((tx) => + tx.insert(BenchmarkTable).values({ + id: Identifier.create("benchmark"), + model: body.model, + agent: body.agent, + result: body.result, + }), + ) + + return Response.json({ success: true }, { status: 200 }) +} diff --git a/packages/console/app/src/routes/black.css b/packages/console/app/src/routes/black.css new file mode 100644 index 00000000000..66bffea5995 --- /dev/null +++ b/packages/console/app/src/routes/black.css @@ -0,0 +1,828 @@ +::view-transition-group(*) { + animation-duration: 250ms; + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +::view-transition-old(root), +::view-transition-new(root) { + animation-duration: 250ms; + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +::view-transition-image-pair(root) { + isolation: isolate; +} + +::view-transition-old(root) { + animation: none; + mix-blend-mode: normal; +} + +::view-transition-new(root) { + animation: none; + mix-blend-mode: normal; +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fade-out { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes fade-in-up { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes reveal-terms { + from { + mask-position: 0% 200%; + } + to { + mask-position: 0% 50%; + } +} + +@keyframes hide-terms { + from { + mask-position: 0% 50%; + } + to { + mask-position: 0% 200%; + } +} + +::view-transition-old(terms-20), +::view-transition-old(terms-100), +::view-transition-old(terms-200) { + mask-image: linear-gradient(to bottom, transparent, black 25% 75%, transparent); + mask-repeat: no-repeat; + mask-size: 100% 200%; + animation: hide-terms 200ms cubic-bezier(0.25, 0, 0.5, 1) forwards; +} + +::view-transition-new(terms-20), +::view-transition-new(terms-100), +::view-transition-new(terms-200) { + mask-image: linear-gradient(to bottom, transparent, black 25% 75%, transparent); + mask-repeat: no-repeat; + mask-position: 0% 200%; + mask-size: 100% 200%; + animation: reveal-terms 300ms cubic-bezier(0.25, 0, 0.5, 1) 50ms forwards; +} + +::view-transition-old(actions-20), +::view-transition-old(actions-100), +::view-transition-old(actions-200) { + animation: fade-out 80ms cubic-bezier(0.4, 0, 0.2, 1) forwards; +} + +::view-transition-new(actions-20), +::view-transition-new(actions-100), +::view-transition-new(actions-200) { + animation: fade-in-up 300ms cubic-bezier(0.16, 1, 0.3, 1) 300ms forwards; + opacity: 0; +} + +::view-transition-group(card-20), +::view-transition-group(card-100), +::view-transition-group(card-200) { + animation-duration: 250ms; + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +[data-page="black"] { + background: #000; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: stretch; + font-family: var(--font-mono); + color: #fff; + + [data-component="header-logo"] { + filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.25)) drop-shadow(0 4px 16px rgba(0, 0, 0, 0.1)); + position: relative; + z-index: 1; + } + + .header-light-rays { + position: absolute; + inset: 0 0 auto 0; + height: 30dvh; + pointer-events: none; + z-index: 0; + } + + [data-component="header"] { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding-top: 40px; + flex-shrink: 0; + } + + [data-component="content"] { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + flex-grow: 1; + + [data-slot="hero"] { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 8px; + margin-top: 40px; + padding: 0 20px; + + @media (min-width: 768px) { + margin-top: 60px; + } + + h1 { + color: rgba(255, 255, 255, 0.92); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 1.45; + margin: 0; + + @media (min-width: 768px) { + font-size: 20px; + } + + @media (max-width: 480px) { + font-size: 14px; + } + } + + p { + color: rgba(255, 255, 255, 0.59); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 1.45; + margin: 0; + + @media (min-width: 768px) { + font-size: 20px; + } + + @media (max-width: 480px) { + font-size: 14px; + } + } + } + + [data-slot="hero-black"] { + margin-top: 40px; + padding: 0 20px; + position: relative; + + @media (min-width: 768px) { + margin-top: 60px; + } + + svg { + width: 100%; + max-width: 590px; + height: auto; + overflow: visible; + filter: drop-shadow(0 0 20px rgba(255, 255, 255, calc(0.1 + var(--hero-black-glow-intensity, 0) * 0.15))) + drop-shadow(0 -5px 30px rgba(255, 255, 255, calc(var(--hero-black-glow-intensity, 0) * 0.2))); + mask-image: linear-gradient(to bottom, black, transparent); + stroke-width: 1.5; + + [data-slot="black-base"] { + fill: url(#hero-black-fill-gradient); + stroke: url(#hero-black-stroke-gradient); + } + + [data-slot="black-glow"] { + fill: url(#hero-black-top-glow); + pointer-events: none; + } + + [data-slot="black-shimmer"] { + fill: url(#hero-black-shimmer-gradient); + pointer-events: none; + mix-blend-mode: overlay; + } + } + } + + [data-slot="cta"] { + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; + text-align: center; + margin-top: -40px; + width: 100%; + + @media (min-width: 768px) { + margin-top: -20px; + } + + [data-slot="heading"] { + color: rgba(255, 255, 255, 0.92); + text-align: center; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 160%; + + span { + display: inline-block; + } + } + [data-slot="subheading"] { + color: rgba(255, 255, 255, 0.59); + font-size: 15px; + font-style: normal; + font-weight: 400; + line-height: 160%; + + @media (min-width: 768px) { + font-size: 18px; + line-height: 160%; + } + } + [data-slot="button"] { + display: inline-flex; + height: 40px; + padding: 0 12px; + justify-content: center; + align-items: center; + gap: 8px; + border-radius: 4px; + background: rgba(255, 255, 255, 0.92); + text-decoration: none; + color: #000; + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: normal; + + &:hover { + background: #e0e0e0; + } + + &:active { + transform: scale(0.98); + } + } + [data-slot="back-soon"] { + color: rgba(255, 255, 255, 0.59); + text-align: center; + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 20.8px */ + } + [data-slot="follow-us"] { + display: inline-flex; + height: 40px; + padding: 0 12px; + justify-content: center; + align-items: center; + gap: 8px; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.17); + color: rgba(255, 255, 255, 0.59); + font-family: var(--font-mono); + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + } + + [data-slot="pricing"] { + display: flex; + flex-direction: column; + gap: 16px; + width: 100%; + max-width: 660px; + padding: 0 20px; + + @media (min-width: 768px) { + padding: 0; + } + } + + [data-slot="pricing-card"] { + display: flex; + flex-direction: column; + gap: 12px; + padding: 24px; + border: 1px solid rgba(255, 255, 255, 0.17); + background: black; + background-clip: padding-box; + border-radius: 4px; + text-decoration: none; + transition: border-color 0.15s ease; + cursor: pointer; + text-align: left; + + @media (max-width: 480px) { + padding: 16px; + } + + &:hover:not(:active) { + border-color: rgba(255, 255, 255, 0.35); + } + + [data-slot="icon"] { + color: rgba(255, 255, 255, 0.59); + } + + [data-slot="price"] { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 8px; + } + + [data-slot="amount"] { + color: rgba(255, 255, 255, 0.92); + font-size: 24px; + font-weight: 500; + } + + [data-slot="period"] { + color: rgba(255, 255, 255, 0.59); + font-size: 14px; + } + + [data-slot="multiplier"] { + color: rgba(255, 255, 255, 0.39); + font-size: 14px; + + &::before { + content: "·"; + margin-right: 8px; + } + } + } + + [data-slot="selected-plan"] { + display: flex; + flex-direction: column; + gap: 32px; + width: 100%; + max-width: 660px; + margin: 0 auto; + position: relative; + background-color: rgba(0, 0, 0, 0.75); + z-index: 1; + + @media (max-width: 480px) { + margin: 0 20px; + width: calc(100% - 40px); + } + } + + [data-slot="selected-card"] { + display: flex; + flex-direction: column; + gap: 12px; + padding: 24px; + border: 1px solid rgba(255, 255, 255, 0.17); + border-radius: 4px; + width: 100%; + + [data-slot="icon"] { + color: rgba(255, 255, 255, 0.59); + } + + [data-slot="price"] { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 8px; + } + + [data-slot="amount"] { + color: rgba(255, 255, 255, 0.92); + font-size: 24px; + font-weight: 500; + } + + [data-slot="period"] { + color: rgba(255, 255, 255, 0.59); + font-size: 14px; + } + + [data-slot="multiplier"] { + color: rgba(255, 255, 255, 0.39); + font-size: 14px; + + &::before { + content: "·"; + margin-right: 8px; + } + } + + [data-slot="terms"] { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 8px; + text-align: left; + + li { + color: rgba(255, 255, 255, 0.59); + font-size: 14px; + line-height: 1.5; + padding-left: 16px; + position: relative; + + &::before { + content: "▪"; + position: absolute; + left: 0; + color: rgba(255, 255, 255, 0.39); + } + + @media (max-width: 768px) { + font-size: 12px; + } + } + } + + [data-slot="actions"] { + display: flex; + gap: 16px; + margin-top: 8px; + + button, + a { + flex: 1; + display: inline-flex; + height: 48px; + padding: 0 16px; + justify-content: center; + align-items: center; + border-radius: 4px; + font-family: var(--font-mono); + font-size: 16px; + font-weight: 400; + text-decoration: none; + cursor: pointer; + } + + [data-slot="cancel"] { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.17); + color: rgba(255, 255, 255, 0.92); + transition-property: background-color, border-color; + transition-duration: 150ms; + transition-timing-function: cubic-bezier(0.25, 0, 0.5, 1); + + &:hover { + background-color: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.25); + } + } + + [data-slot="continue"] { + background: rgb(255, 255, 255); + color: rgb(0, 0, 0); + transition: background-color 150ms cubic-bezier(0.25, 0, 0.5, 1); + + &:hover { + background: rgba(255, 255, 255, 0.9); + } + } + } + } + + [data-slot="fine-print"] { + color: rgba(255, 255, 255, 0.39); + text-align: center; + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 20.8px */ + font-style: italic; + + a { + color: rgba(255, 255, 255, 0.39); + text-decoration: underline; + } + } + } + + /* Subscribe page styles */ + [data-slot="subscribe-form"] { + display: flex; + flex-direction: column; + gap: 32px; + align-items: center; + margin-top: -18px; + width: 100%; + max-width: 660px; + padding: 0 20px; + + @media (min-width: 768px) { + margin-top: 40px; + padding: 0; + } + + [data-slot="form-card"] { + width: 100%; + border: 1px solid rgba(255, 255, 255, 0.17); + border-radius: 4px; + padding: 24px; + display: flex; + flex-direction: column; + gap: 20px; + } + + [data-slot="plan-header"] { + display: flex; + flex-direction: column; + gap: 8px; + } + + [data-slot="title"] { + color: rgba(255, 255, 255, 0.92); + font-size: 16px; + font-weight: 400; + margin-bottom: 8px; + } + + [data-slot="icon"] { + color: rgba(255, 255, 255, 0.59); + isolation: isolate; + transform: translateZ(0); + } + + [data-slot="price"] { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 8px; + } + + [data-slot="amount"] { + color: rgba(255, 255, 255, 0.92); + font-size: 24px; + font-weight: 500; + } + + [data-slot="period"] { + color: rgba(255, 255, 255, 0.59); + font-size: 14px; + } + + [data-slot="multiplier"] { + color: rgba(255, 255, 255, 0.39); + font-size: 14px; + + &::before { + content: "·"; + margin: 0 8px; + } + } + + [data-slot="divider"] { + height: 1px; + background: rgba(255, 255, 255, 0.17); + } + + [data-slot="section-title"] { + color: rgba(255, 255, 255, 0.92); + font-size: 16px; + font-weight: 400; + } + + [data-slot="checkout-form"] { + display: flex; + flex-direction: column; + gap: 20px; + } + + [data-slot="error"] { + color: #ff6b6b; + font-size: 14px; + } + + [data-slot="submit-button"] { + width: 100%; + height: 48px; + background: rgba(255, 255, 255, 0.92); + border: none; + border-radius: 4px; + color: #000; + font-family: var(--font-mono); + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: background 0.15s ease; + + &:hover:not(:disabled) { + background: #e0e0e0; + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + } + + [data-slot="charge-notice"] { + color: #d4a500; + font-size: 14px; + text-align: center; + } + + [data-slot="loading"] { + display: flex; + justify-content: center; + padding: 40px 0; + + p { + color: rgba(255, 255, 255, 0.59); + font-size: 14px; + } + } + + [data-slot="fine-print"] { + color: rgba(255, 255, 255, 0.39); + text-align: center; + font-size: 13px; + font-style: italic; + view-transition-name: fine-print; + + a { + color: rgba(255, 255, 255, 0.39); + text-decoration: underline; + } + } + + [data-slot="workspace-picker"] { + [data-slot="workspace-list"] { + width: 100%; + padding: 0; + margin: 0; + list-style: none; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + align-self: stretch; + outline: none; + overflow-y: auto; + max-height: 240px; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + + [data-slot="workspace-item"] { + width: 100%; + display: flex; + padding: 8px 12px; + align-items: center; + gap: 8px; + align-self: stretch; + cursor: pointer; + + [data-slot="selected-icon"] { + visibility: hidden; + color: rgba(255, 255, 255, 0.39); + font-family: "IBM Plex Mono", monospace; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; + } + + span:last-child { + color: rgba(255, 255, 255, 0.92); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; + } + + &:hover, + &[data-active="true"] { + background: #161616; + + [data-slot="selected-icon"] { + visibility: visible; + } + } + } + } + } + } + } + + [data-component="footer"] { + display: flex; + flex-direction: column; + width: 100%; + justify-content: center; + align-items: center; + gap: 24px; + flex-shrink: 0; + + @media (min-width: 768px) { + height: 120px; + } + + [data-slot="footer-content"] { + display: flex; + gap: 24px; + align-items: center; + justify-content: center; + + @media (min-width: 768px) { + gap: 40px; + } + + span, + a { + color: rgba(255, 255, 255, 0.39); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + } + + [data-slot="github-stars"] { + color: rgba(255, 255, 255, 0.25); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + } + + [data-slot="anomaly"] { + display: none; + + @media (min-width: 768px) { + display: block; + } + } + } + [data-slot="anomaly-alt"] { + color: rgba(255, 255, 255, 0.39); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + margin-bottom: 24px; + + a { + color: rgba(255, 255, 255, 0.39); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + } + + @media (min-width: 768px) { + display: none; + } + } + } +} diff --git a/packages/console/app/src/routes/black.tsx b/packages/console/app/src/routes/black.tsx new file mode 100644 index 00000000000..b991a60a77c --- /dev/null +++ b/packages/console/app/src/routes/black.tsx @@ -0,0 +1,285 @@ +import { A, createAsync, RouteSectionProps } from "@solidjs/router" +import { Title, Meta, Link } from "@solidjs/meta" +import { createMemo, createSignal } from "solid-js" +import { github } from "~/lib/github" +import { config } from "~/config" +import Spotlight, { defaultConfig, type SpotlightAnimationState } from "~/component/spotlight" +import "./black.css" + +export default function BlackLayout(props: RouteSectionProps) { + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()!.stars!) + : config.github.starsFormatted.compact, + ) + + const [spotlightAnimationState, setSpotlightAnimationState] = createSignal({ + time: 0, + intensity: 0.5, + pulseValue: 1, + }) + + const svgLightingValues = createMemo(() => { + const state = spotlightAnimationState() + const t = state.time + + const wave1 = Math.sin(t * 1.5) * 0.5 + 0.5 + const wave2 = Math.sin(t * 2.3 + 1.2) * 0.5 + 0.5 + const wave3 = Math.sin(t * 0.8 + 2.5) * 0.5 + 0.5 + + const shimmerPos = Math.sin(t * 0.7) * 0.5 + 0.5 + const glowIntensity = Math.max(state.intensity * state.pulseValue * 0.35, 0.15) + const fillOpacity = Math.max(0.1 + wave1 * 0.08 * state.pulseValue, 0.12) + const strokeBrightness = Math.max(55 + wave2 * 25 * state.pulseValue, 60) + + const shimmerIntensity = Math.max(wave3 * 0.15 * state.pulseValue, 0.08) + + return { + glowIntensity, + fillOpacity, + strokeBrightness, + shimmerPos, + shimmerIntensity, + } + }) + + const svgLightingStyle = createMemo(() => { + const values = svgLightingValues() + return { + "--hero-black-glow-intensity": values.glowIntensity.toFixed(3), + "--hero-black-stroke-brightness": `${values.strokeBrightness.toFixed(0)}%`, + } as Record + }) + + const handleAnimationFrame = (state: SpotlightAnimationState) => { + setSpotlightAnimationState(state) + } + + const spotlightConfig = () => defaultConfig + + return ( +
+ OpenCode Black | Access all the world's best coding models + + + + + + + + + + + + + + +
+ + + opencode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Access all the world's best coding models

+

Including Claude, GPT, Gemini and more

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {props.children} +
+ +
+ ) +} diff --git a/packages/console/app/src/routes/black/common.tsx b/packages/console/app/src/routes/black/common.tsx new file mode 100644 index 00000000000..39844abee38 --- /dev/null +++ b/packages/console/app/src/routes/black/common.tsx @@ -0,0 +1,62 @@ +import { Match, Switch } from "solid-js" + +export const plans = [ + { id: "20", multiplier: null }, + { id: "100", multiplier: "5x more usage than Black 20" }, + { id: "200", multiplier: "20x more usage than Black 20" }, +] as const + +export type PlanID = (typeof plans)[number]["id"] +export type Plan = (typeof plans)[number] + +export function PlanIcon(props: { plan: string }) { + return ( + + + + Black 20 plan + + + + + + Black 100 plan + + + + + + + + + Black 200 plan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/packages/console/app/src/routes/black/index.tsx b/packages/console/app/src/routes/black/index.tsx new file mode 100644 index 00000000000..5ea5c3e9268 --- /dev/null +++ b/packages/console/app/src/routes/black/index.tsx @@ -0,0 +1,108 @@ +import { A, useSearchParams } from "@solidjs/router" +import { Title } from "@solidjs/meta" +import { createMemo, createSignal, For, Match, onMount, Show, Switch } from "solid-js" +import { PlanIcon, plans } from "./common" + +export default function Black() { + const [params] = useSearchParams() + const [selected, setSelected] = createSignal((params.plan as string) || null) + const [mounted, setMounted] = createSignal(false) + const selectedPlan = createMemo(() => plans.find((p) => p.id === selected())) + + onMount(() => { + requestAnimationFrame(() => setMounted(true)) + }) + + const transition = (action: () => void) => { + if (mounted() && "startViewTransition" in document) { + ;(document as any).startViewTransition(action) + return + } + + action() + } + + const select = (planId: string) => { + if (selected() === planId) { + return + } + + transition(() => setSelected(planId)) + } + + const cancel = () => { + transition(() => setSelected(null)) + } + + return ( + <> + opencode +
+ + +
+ + {(plan) => ( + + )} + +
+
+ + {(plan) => ( +
+
+
+ +
+

+ ${plan().id}{" "} + per person billed monthly + + {plan().multiplier} + +

+
    +
  • Your subscription will not start immediately
  • +
  • You will be added to the waitlist and activated soon
  • +
  • Your card will be only charged when your subscription is activated
  • +
  • Usage limits apply, heavily automated use may reach limits sooner
  • +
  • Subscriptions for individuals, contact Enterprise for teams
  • +
  • Limits may be adjusted and plans may be discontinued in the future
  • +
  • Cancel your subscription at anytime
  • +
+
+ + + Continue + +
+
+
+ )} +
+
+

+ Prices shown don't include applicable tax · Terms of Service +

+
+ + ) +} diff --git a/packages/console/app/src/routes/black/subscribe/[plan].tsx b/packages/console/app/src/routes/black/subscribe/[plan].tsx new file mode 100644 index 00000000000..a7cf92a25ec --- /dev/null +++ b/packages/console/app/src/routes/black/subscribe/[plan].tsx @@ -0,0 +1,449 @@ +import { A, createAsync, query, redirect, useParams } from "@solidjs/router" +import { Title } from "@solidjs/meta" +import { createEffect, createSignal, For, Match, Show, Switch } from "solid-js" +import { type Stripe, type PaymentMethod, loadStripe } from "@stripe/stripe-js" +import { Elements, PaymentElement, useStripe, useElements, AddressElement } from "solid-stripe" +import { PlanID, plans } from "../common" +import { getActor, useAuthSession } from "~/context/auth" +import { withActor } from "~/context/auth.withActor" +import { Actor } from "@opencode-ai/console-core/actor.js" +import { and, Database, eq, isNull } from "@opencode-ai/console-core/drizzle/index.js" +import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js" +import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" +import { createList } from "solid-list" +import { Modal } from "~/component/modal" +import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js" +import { Billing } from "@opencode-ai/console-core/billing.js" + +const plansMap = Object.fromEntries(plans.map((p) => [p.id, p])) as Record +const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY!) + +const getWorkspaces = query(async (plan: string) => { + "use server" + const actor = await getActor() + if (actor.type === "public") throw redirect("/auth/authorize?continue=/black/subscribe/" + plan) + return withActor(async () => { + return Database.use((tx) => + tx + .select({ + id: WorkspaceTable.id, + name: WorkspaceTable.name, + slug: WorkspaceTable.slug, + billing: { + customerID: BillingTable.customerID, + paymentMethodID: BillingTable.paymentMethodID, + paymentMethodType: BillingTable.paymentMethodType, + paymentMethodLast4: BillingTable.paymentMethodLast4, + subscriptionID: BillingTable.subscriptionID, + timeSubscriptionBooked: BillingTable.timeSubscriptionBooked, + }, + }) + .from(UserTable) + .innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id)) + .innerJoin(BillingTable, eq(WorkspaceTable.id, BillingTable.workspaceID)) + .where( + and( + eq(UserTable.accountID, Actor.account()), + isNull(WorkspaceTable.timeDeleted), + isNull(UserTable.timeDeleted), + ), + ), + ) + }) +}, "black.subscribe.workspaces") + +const createSetupIntent = async (input: { plan: string; workspaceID: string }) => { + "use server" + const { plan, workspaceID } = input + + if (!plan || !["20", "100", "200"].includes(plan)) return { error: "Invalid plan" } + if (!workspaceID) return { error: "Workspace ID is required" } + + return withActor(async () => { + const session = await useAuthSession() + const account = session.data.account?.[session.data.current ?? ""] + const email = account?.email + + const customer = await Database.use((tx) => + tx + .select({ + customerID: BillingTable.customerID, + subscriptionID: BillingTable.subscriptionID, + }) + .from(BillingTable) + .where(eq(BillingTable.workspaceID, workspaceID)) + .then((rows) => rows[0]), + ) + if (customer?.subscriptionID) { + return { error: "This workspace already has a subscription" } + } + + let customerID = customer?.customerID + if (!customerID) { + const customer = await Billing.stripe().customers.create({ + email, + metadata: { + workspaceID, + }, + }) + customerID = customer.id + await Database.use((tx) => + tx + .update(BillingTable) + .set({ + customerID, + }) + .where(eq(BillingTable.workspaceID, workspaceID)), + ) + } + + const intent = await Billing.stripe().setupIntents.create({ + customer: customerID, + payment_method_types: ["card"], + metadata: { + workspaceID, + }, + }) + + return { clientSecret: intent.client_secret ?? undefined } + }, workspaceID) +} + +const bookSubscription = async (input: { + workspaceID: string + plan: PlanID + paymentMethodID: string + paymentMethodType: string + paymentMethodLast4?: string +}) => { + "use server" + return withActor( + () => + Database.use((tx) => + tx + .update(BillingTable) + .set({ + paymentMethodID: input.paymentMethodID, + paymentMethodType: input.paymentMethodType, + paymentMethodLast4: input.paymentMethodLast4, + subscriptionPlan: input.plan, + timeSubscriptionBooked: new Date(), + }) + .where(eq(BillingTable.workspaceID, input.workspaceID)), + ), + input.workspaceID, + ) +} + +interface SuccessData { + plan: string + paymentMethodType: string + paymentMethodLast4?: string +} + +function Failure(props: { message: string }) { + return ( +
+

Uh oh! {props.message}

+
+ ) +} + +function Success(props: SuccessData) { + return ( +
+

You're on the OpenCode Black waitlist

+
+
+
Subscription plan
+
OpenCode Black {props.plan}
+
+
+
Amount
+
${props.plan} per month
+
+
+
Payment method
+
+ {props.paymentMethodType}}> + + {props.paymentMethodType} - {props.paymentMethodLast4} + + +
+
+
+
Date joined
+
{new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
+
+
+

Your card will be charged when your subscription is activated

+
+ ) +} + +function IntentForm(props: { plan: PlanID; workspaceID: string; onSuccess: (data: SuccessData) => void }) { + const stripe = useStripe() + const elements = useElements() + const [error, setError] = createSignal(undefined) + const [loading, setLoading] = createSignal(false) + + const handleSubmit = async (e: Event) => { + e.preventDefault() + if (!stripe() || !elements()) return + + setLoading(true) + setError(undefined) + + const result = await elements()!.submit() + if (result.error) { + setError(result.error.message ?? "An error occurred") + setLoading(false) + return + } + + const { error: confirmError, setupIntent } = await stripe()!.confirmSetup({ + elements: elements()!, + confirmParams: { + expand: ["payment_method"], + payment_method_data: { + allow_redisplay: "always", + }, + }, + redirect: "if_required", + }) + + if (confirmError) { + setError(confirmError.message ?? "An error occurred") + setLoading(false) + return + } + + if (setupIntent?.status === "succeeded") { + const pm = setupIntent.payment_method as PaymentMethod + + await bookSubscription({ + workspaceID: props.workspaceID, + plan: props.plan, + paymentMethodID: pm.id, + paymentMethodType: pm.type, + paymentMethodLast4: pm.card?.last4, + }) + + props.onSuccess({ + plan: props.plan, + paymentMethodType: pm.type, + paymentMethodLast4: pm.card?.last4, + }) + } + + setLoading(false) + } + + return ( +
+ + + +

{error()}

+
+ +

You will only be charged when your subscription is activated

+ + ) +} + +export default function BlackSubscribe() { + const params = useParams() + const planData = plansMap[(params.plan as PlanID) ?? "20"] ?? plansMap["20"] + const plan = planData.id + + const workspaces = createAsync(() => getWorkspaces(plan)) + const [selectedWorkspace, setSelectedWorkspace] = createSignal(undefined) + const [success, setSuccess] = createSignal(undefined) + const [failure, setFailure] = createSignal(undefined) + const [clientSecret, setClientSecret] = createSignal(undefined) + const [stripe, setStripe] = createSignal(undefined) + + // Resolve stripe promise once + createEffect(() => { + stripePromise.then((s) => { + if (s) setStripe(s) + }) + }) + + // Auto-select if only one workspace + createEffect(() => { + const ws = workspaces() + if (ws?.length === 1 && !selectedWorkspace()) { + setSelectedWorkspace(ws[0].id) + } + }) + + // Fetch setup intent when workspace is selected (unless workspace already has payment method) + createEffect(async () => { + const id = selectedWorkspace() + if (!id) return + + const ws = workspaces()?.find((w) => w.id === id) + if (ws?.billing?.subscriptionID) { + setFailure("This workspace already has a subscription") + return + } + if (ws?.billing?.paymentMethodID) { + if (!ws?.billing?.timeSubscriptionBooked) { + await bookSubscription({ + workspaceID: id, + plan: planData.id, + paymentMethodID: ws.billing.paymentMethodID!, + paymentMethodType: ws.billing.paymentMethodType!, + paymentMethodLast4: ws.billing.paymentMethodLast4 ?? undefined, + }) + } + setSuccess({ + plan: planData.id, + paymentMethodType: ws.billing.paymentMethodType!, + paymentMethodLast4: ws.billing.paymentMethodLast4 ?? undefined, + }) + return + } + + const result = await createSetupIntent({ plan, workspaceID: id }) + if (result.error) { + setFailure(result.error) + } else if ("clientSecret" in result) { + setClientSecret(result.clientSecret) + } + }) + + // Keyboard navigation for workspace picker + const { active, setActive, onKeyDown } = createList({ + items: () => workspaces()?.map((w) => w.id) ?? [], + initialActive: null, + }) + + const handleSelectWorkspace = (id: string) => { + setSelectedWorkspace(id) + } + + let listRef: HTMLUListElement | undefined + + // Show workspace picker if multiple workspaces and none selected + const showWorkspacePicker = () => { + const ws = workspaces() + return ws && ws.length > 1 && !selectedWorkspace() + } + + return ( + <> + Subscribe to OpenCode Black +
+
+ + {(data) => } + {(data) => } + + <> +
+

Subscribe to OpenCode Black

+

+ ${planData.id} per month + + {planData.multiplier} + +

+
+
+

Payment method

+ + +

{selectedWorkspace() ? "Loading payment form..." : "Select a workspace to continue"}

+
+ } + > + + + + + +
+
+
+ + {/* Workspace picker modal */} + {}} title="Select a workspace for this plan"> +
+
    { + if (e.key === "Enter" && active()) { + handleSelectWorkspace(active()!) + } else { + onKeyDown(e) + } + }} + > + + {(workspace) => ( +
  • setActive(workspace.id)} + onClick={() => handleSelectWorkspace(workspace.id)} + > + [*] + {workspace.name || workspace.slug} +
  • + )} +
    +
+
+
+

+ Prices shown don't include applicable tax · Terms of Service +

+
+ + ) +} diff --git a/packages/console/app/src/routes/black/workspace.css b/packages/console/app/src/routes/black/workspace.css new file mode 100644 index 00000000000..bf9d948786f --- /dev/null +++ b/packages/console/app/src/routes/black/workspace.css @@ -0,0 +1,214 @@ +[data-page="black"] { + background: #000; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: stretch; + font-family: var(--font-mono); + color: #fff; + + [data-component="header-gradient"] { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 288px; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.16) 0%, rgba(0, 0, 0, 0) 100%); + } + + [data-component="header"] { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding-top: 40px; + flex-shrink: 0; + + /* [data-component="header-logo"] { */ + /* } */ + } + + [data-component="content"] { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + flex-grow: 1; + + [data-slot="hero-black"] { + margin-top: 110px; + + @media (min-width: 768px) { + margin-top: 150px; + } + } + + [data-slot="select-workspace"] { + display: flex; + margin-top: -24px; + width: 100%; + max-width: 480px; + height: 305px; + padding: 32px 20px 0 20px; + flex-direction: column; + align-items: flex-start; + gap: 24px; + + border: 1px solid #303030; + background: #0a0a0a; + box-shadow: + 0 100px 80px 0 rgba(0, 0, 0, 0.04), + 0 41.778px 33.422px 0 rgba(0, 0, 0, 0.05), + 0 22.336px 17.869px 0 rgba(0, 0, 0, 0.06), + 0 12.522px 10.017px 0 rgba(0, 0, 0, 0.08), + 0 6.65px 5.32px 0 rgba(0, 0, 0, 0.09), + 0 2.767px 2.214px 0 rgba(0, 0, 0, 0.13); + + [data-slot="select-workspace-title"] { + flex-shrink: 0; + align-self: stretch; + color: rgba(255, 255, 255, 0.59); + text-align: center; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 25.6px */ + } + + [data-slot="workspaces"] { + width: 100%; + padding: 0; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + align-self: stretch; + outline: none; + overflow-y: auto; + flex: 1; + min-height: 0; + + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } + + [data-slot="workspace"] { + width: 100%; + display: flex; + padding: 8px 12px; + align-items: center; + gap: 8px; + align-self: stretch; + cursor: pointer; + + [data-slot="selected-icon"] { + visibility: hidden; + color: rgba(255, 255, 255, 0.39); + font-family: "IBM Plex Mono"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 25.6px */ + } + + a { + color: rgba(255, 255, 255, 0.92); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 25.6px */ + text-decoration: none; + } + } + + [data-slot="workspace"]:hover, + [data-slot="workspace"][data-active="true"] { + background: #161616; + + [data-slot="selected-icon"] { + visibility: visible; + } + } + } + } + } + + [data-component="footer"] { + display: flex; + flex-direction: column; + width: 100%; + justify-content: center; + align-items: center; + gap: 24px; + flex-shrink: 0; + + @media (min-width: 768px) { + height: 120px; + } + + [data-slot="footer-content"] { + display: flex; + gap: 24px; + align-items: center; + justify-content: center; + + @media (min-width: 768px) { + gap: 40px; + } + + span, + a { + color: rgba(255, 255, 255, 0.39); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + } + + [data-slot="github-stars"] { + color: rgba(255, 255, 255, 0.25); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + } + + [data-slot="anomaly"] { + display: none; + + @media (min-width: 768px) { + display: block; + } + } + } + [data-slot="anomaly-alt"] { + color: rgba(255, 255, 255, 0.39); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + margin-bottom: 24px; + + a { + color: rgba(255, 255, 255, 0.39); + font-family: "JetBrains Mono Nerd Font"; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + } + + @media (min-width: 768px) { + display: none; + } + } + } +} diff --git a/packages/console/app/src/routes/black/workspace.tsx b/packages/console/app/src/routes/black/workspace.tsx new file mode 100644 index 00000000000..0eca8cd11ab --- /dev/null +++ b/packages/console/app/src/routes/black/workspace.tsx @@ -0,0 +1,229 @@ +import { A, createAsync, useNavigate } from "@solidjs/router" +import "./workspace.css" +import { Title } from "@solidjs/meta" +import { github } from "~/lib/github" +import { createEffect, createMemo, For, onMount } from "solid-js" +import { config } from "~/config" +import { createList } from "solid-list" + +export default function BlackWorkspace() { + const navigate = useNavigate() + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()!.stars!) + : config.github.starsFormatted.compact, + ) + + // TODO: Frank, replace with real workspaces + const workspaces = [ + { name: "Workspace 1", id: "wrk_123" }, + { name: "Workspace 2", id: "wrk_456" }, + { name: "Workspace 3", id: "wrk_789" }, + { name: "Workspace 4", id: "wrk_111" }, + { name: "Workspace 5", id: "wrk_222" }, + { name: "Workspace 6", id: "wrk_333" }, + { name: "Workspace 7", id: "wrk_444" }, + { name: "Workspace 8", id: "wrk_555" }, + ] + + let listRef: HTMLUListElement | undefined + + const { active, setActive, onKeyDown } = createList({ + items: () => workspaces.map((w) => w.id), + initialActive: workspaces[0]?.id ?? null, + handleTab: true, + }) + + onMount(() => { + listRef?.focus() + }) + + createEffect(() => { + const id = active() + if (!id || !listRef) return + const el = listRef.querySelector(`[data-id="${id}"]`) + el?.scrollIntoView({ block: "nearest" }) + }) + + return ( +
+ opencode +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+

Select a workspace for this plan

+
    { + if (e.key === "Enter" && active()) { + navigate(`/black/workspace/${active()}`) + } else if (e.key === "Tab") { + e.preventDefault() + onKeyDown(e) + } else { + onKeyDown(e) + } + }} + > + + {(workspace) => ( +
  • setActive(workspace.id)} + onClick={() => navigate(`/black/workspace/${workspace.id}`)} + > + [*] + {workspace.name} +
  • + )} +
    +
+
+
+ +
+ ) +} diff --git a/packages/console/app/src/routes/brand/index.css b/packages/console/app/src/routes/brand/index.css new file mode 100644 index 00000000000..2bfe5711aa6 --- /dev/null +++ b/packages/console/app/src/routes/brand/index.css @@ -0,0 +1,555 @@ +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); + + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } +} + +[data-page="enterprise"], +[data-page="legal"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-weak-hover: hsl(0, 8%, 94%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 60%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + --color-text-success: hsl(119, 100%, 35%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); + --color-success: hsl(142, 76%, 36%); + + background: var(--color-background); + font-family: var(--font-mono); + color: var(--color-text); + padding-bottom: 5rem; + + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-weak-hover: hsl(0, 6%, 15%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + --color-text-success: hsl(119, 60%, 72%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); + --color-success: hsl(142, 76%, 46%); + } + + /* Header and Footer styles - copied from index.css */ + [data-component="top"] { + padding: 24px 5rem; + height: 80px; + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + z-index: 10; + + @media (max-width: 60rem) { + padding: 24px 1.5rem; + } + + img { + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + align-items: center; + gap: 48px; + + @media (max-width: 55rem) { + gap: 32px; + } + + @media (max-width: 48rem) { + gap: 24px; + } + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + [data-slot="cta-button"] { + background: var(--color-background-strong); + color: var(--color-text-inverted); + padding: 8px 16px 8px 10px; + border-radius: 4px; + font-weight: 500; + text-decoration: none; + display: flex; + align-items: center; + gap: 8px; + + @media (max-width: 55rem) { + display: none; + } + } + [data-slot="cta-button"]:hover { + background: var(--color-background-strong-hover); + text-decoration: none; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile"] { + button > svg { + color: var(--color-icon); + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + margin-right: -8px; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + flex-direction: row; + + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + [data-slot="cell"] { + flex: 1; + text-align: center; + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + + [data-slot="cell"] + [data-slot="cell"] { + border-left: 1px solid var(--color-border-weak); + + @media (max-width: 40rem) { + border-left: none; + } + } + + /* Mobile: third column on its own row */ + @media (max-width: 25rem) { + flex-wrap: wrap; + + [data-slot="cell"] { + flex: 1 0 100%; + border-left: none; + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; + } + } + } + + [data-component="container"] { + max-width: 67.5rem; + margin: 0 auto; + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { + } + + [data-component="brand-content"] { + padding: 4rem 5rem; + + h1 { + font-size: 1.5rem; + font-weight: 700; + color: var(--color-text-strong); + margin-bottom: 1rem; + } + + h3 { + font-size: 1.25rem; + font-weight: 500; + color: var(--color-text-strong); + margin: 2rem 0 1rem 0; + } + + p { + line-height: 1.6; + margin-bottom: 2.5rem; + color: var(--color-text); + } + + [data-component="download-button"] { + padding: 8px 12px 8px 20px; + background: var(--color-background-strong); + color: var(--color-text-inverted); + border: none; + border-radius: 4px; + font-weight: 500; + cursor: pointer; + display: flex; + width: fit-content; + align-items: center; + gap: 12px; + transition: all 0.2s ease; + text-decoration: none; + + &:hover:not(:disabled) { + background: var(--color-background-strong-hover); + } + + &:active { + transform: scale(0.98); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + [data-component="brand-grid"] { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin-top: 4rem; + margin-bottom: 2rem; + } + + [data-component="brand-grid"] img { + width: 100%; + height: auto; + display: block; + border-radius: 4px; + border: 1px solid var(--color-border-weak); + } + + [data-component="brand-grid"] > div { + position: relative; + } + + [data-component="actions"] { + position: absolute; + background: rgba(4, 0, 0, 0.08); + border-radius: 4px; + bottom: 0; + right: 0; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + gap: 16px; + opacity: 0; + transition: opacity 0.2s ease; + + @media (max-width: 40rem) { + position: static; + opacity: 1; + background: none; + margin-top: 1rem; + justify-content: start; + } + } + + [data-component="brand-grid"] > div:hover [data-component="actions"] { + opacity: 1; + + @media (max-width: 40rem) { + opacity: 1; + } + } + + [data-component="actions"] button { + padding: 6px 12px; + background: var(--color-background); + color: var(--color-text); + border: none; + border-radius: 4px; + font-weight: 500; + display: flex; + align-items: center; + gap: 12px; + transition: all 0.2s ease; + cursor: pointer; + box-shadow: + 0 0 0 1px rgba(19, 16, 16, 0.08), + 0 6px 8px -4px rgba(19, 16, 16, 0.12), + 0 4px 3px -2px rgba(19, 16, 16, 0.12), + 0 1px 2px -1px rgba(19, 16, 16, 0.12); + + @media (max-width: 40rem) { + box-shadow: 0 0 0 1px rgba(19, 16, 16, 0.16); + } + + &:hover { + background: var(--color-background); + } + + &:active { + transform: scale(0.98); + box-shadow: + 0 0 0 1px rgba(19, 16, 16, 0.08), + 0 6px 8px -8px rgba(19, 16, 16, 0.5); + } + } + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + } + + [data-component="faq"] { + border-top: 1px solid var(--color-border-weak); + padding: 4rem 5rem; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + [data-slot="section-title"] { + margin-bottom: 24px; + + h3 { + font-size: 16px; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 12px; + } + + p { + margin-bottom: 12px; + color: var(--color-text); + } + } + + ul { + padding: 0; + + li { + list-style: none; + margin-bottom: 24px; + line-height: 200%; + + @media (max-width: 60rem) { + line-height: 180%; + } + } + } + + [data-slot="faq-question"] { + display: flex; + gap: 16px; + margin-bottom: 8px; + color: var(--color-text-strong); + font-weight: 500; + cursor: pointer; + background: none; + border: none; + padding: 0; + + [data-slot="faq-icon-plus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: none; + } + [data-expanded] & { + display: block; + } + } + [data-slot="faq-question-text"] { + flex-grow: 1; + text-align: left; + } + } + + [data-slot="faq-answer"] { + margin-left: 40px; + margin-bottom: 32px; + color: var(--color-text); + } + } + + [data-component="legal"] { + color: var(--color-text-weak); + text-align: center; + padding: 2rem 5rem; + display: flex; + gap: 32px; + justify-content: center; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + a { + color: var(--color-text-weak); + text-decoration: none; + } + + a:hover { + color: var(--color-text); + text-decoration: underline; + } + } + + a { + color: var(--color-text-strong); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + + &:hover { + text-decoration-thickness: 2px; + } + } +} diff --git a/packages/console/app/src/routes/brand/index.tsx b/packages/console/app/src/routes/brand/index.tsx new file mode 100644 index 00000000000..6aac4517a0a --- /dev/null +++ b/packages/console/app/src/routes/brand/index.tsx @@ -0,0 +1,252 @@ +import "./index.css" +import { Title, Meta, Link } from "@solidjs/meta" +import { Header } from "~/component/header" +import { config } from "~/config" +import { Footer } from "~/component/footer" +import { Legal } from "~/component/legal" +import previewLogoLight from "../../asset/brand/preview-opencode-logo-light.png" +import previewLogoDark from "../../asset/brand/preview-opencode-logo-dark.png" +import previewWordmarkLight from "../../asset/brand/preview-opencode-wordmark-light.png" +import previewWordmarkDark from "../../asset/brand/preview-opencode-wordmark-dark.png" +import previewWordmarkSimpleLight from "../../asset/brand/preview-opencode-wordmark-simple-light.png" +import previewWordmarkSimpleDark from "../../asset/brand/preview-opencode-wordmark-simple-dark.png" +import logoLightPng from "../../asset/brand/opencode-logo-light.png" +import logoDarkPng from "../../asset/brand/opencode-logo-dark.png" +import wordmarkLightPng from "../../asset/brand/opencode-wordmark-light.png" +import wordmarkDarkPng from "../../asset/brand/opencode-wordmark-dark.png" +import wordmarkSimpleLightPng from "../../asset/brand/opencode-wordmark-simple-light.png" +import wordmarkSimpleDarkPng from "../../asset/brand/opencode-wordmark-simple-dark.png" +import logoLightSvg from "../../asset/brand/opencode-logo-light.svg" +import logoDarkSvg from "../../asset/brand/opencode-logo-dark.svg" +import wordmarkLightSvg from "../../asset/brand/opencode-wordmark-light.svg" +import wordmarkDarkSvg from "../../asset/brand/opencode-wordmark-dark.svg" +import wordmarkSimpleLightSvg from "../../asset/brand/opencode-wordmark-simple-light.svg" +import wordmarkSimpleDarkSvg from "../../asset/brand/opencode-wordmark-simple-dark.svg" +const brandAssets = "/opencode-brand-assets.zip" + +export default function Brand() { + const downloadFile = async (url: string, filename: string) => { + try { + const response = await fetch(url) + const blob = await response.blob() + const blobUrl = window.URL.createObjectURL(blob) + + const link = document.createElement("a") + link.href = blobUrl + link.download = filename + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + + window.URL.revokeObjectURL(blobUrl) + } catch (error) { + console.error("Download failed:", error) + const link = document.createElement("a") + link.href = url + link.target = "_blank" + link.rel = "noopener noreferrer" + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + } + } + + return ( +
+ OpenCode | Brand + + +
+
+ +
+
+

Brand guidelines

+

Resources and assets to help you work with the OpenCode brand.

+ + +
+
+ OpenCode brand guidelines +
+ + +
+
+
+ OpenCode brand guidelines +
+ + +
+
+
+ OpenCode brand guidelines +
+ + +
+
+
+ OpenCode brand guidelines +
+ + +
+
+
+ OpenCode brand guidelines +
+ + +
+
+
+ OpenCode brand guidelines +
+ + +
+
+
+
+
+
+
+ +
+ ) +} diff --git a/packages/console/app/src/routes/changelog/index.css b/packages/console/app/src/routes/changelog/index.css new file mode 100644 index 00000000000..29020a924e5 --- /dev/null +++ b/packages/console/app/src/routes/changelog/index.css @@ -0,0 +1,477 @@ +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); + + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } +} + +[data-page="changelog"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-weak-hover: hsl(0, 8%, 94%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 60%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); + + background: var(--color-background); + font-family: var(--font-mono); + color: var(--color-text); + padding-bottom: 5rem; + + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-weak-hover: hsl(0, 6%, 15%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); + } + + /* Header styles - copied from download */ + [data-component="top"] { + padding: 24px 5rem; + height: 80px; + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + z-index: 10; + + @media (max-width: 60rem) { + padding: 24px 1.5rem; + } + + img { + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + align-items: center; + gap: 48px; + + @media (max-width: 55rem) { + gap: 32px; + } + + @media (max-width: 48rem) { + gap: 24px; + } + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + [data-slot="cta-button"] { + background: var(--color-background-strong); + color: var(--color-text-inverted); + padding: 8px 16px; + border-radius: 4px; + font-weight: 500; + text-decoration: none; + + @media (max-width: 55rem) { + display: none; + } + } + [data-slot="cta-button"]:hover { + background: var(--color-background-strong-hover); + text-decoration: none; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile"] { + button > svg { + color: var(--color-icon); + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + margin-right: -8px; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + flex-direction: row; + margin-top: 4rem; + + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + [data-slot="cell"] { + flex: 1; + text-align: center; + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + + [data-slot="cell"] + [data-slot="cell"] { + border-left: 1px solid var(--color-border-weak); + + @media (max-width: 40rem) { + border-left: none; + } + } + + @media (max-width: 25rem) { + flex-wrap: wrap; + + [data-slot="cell"] { + flex: 1 0 100%; + border-left: none; + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; + } + } + } + + [data-component="container"] { + max-width: 67.5rem; + margin: 0 auto; + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { + padding: 6rem 5rem; + + @media (max-width: 60rem) { + padding: 4rem 1.5rem; + } + } + + [data-component="legal"] { + color: var(--color-text-weak); + text-align: center; + padding: 2rem 5rem; + display: flex; + gap: 32px; + justify-content: center; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + a { + color: var(--color-text-weak); + text-decoration: none; + } + + a:hover { + color: var(--color-text); + text-decoration: underline; + } + } + + /* Changelog Hero */ + [data-component="changelog-hero"] { + margin-bottom: 4rem; + padding-bottom: 2rem; + border-bottom: 1px solid var(--color-border-weak); + + @media (max-width: 50rem) { + margin-bottom: 2rem; + padding-bottom: 1.5rem; + } + + h1 { + font-size: 1.5rem; + font-weight: 700; + color: var(--color-text-strong); + margin-bottom: 8px; + } + + p { + color: var(--color-text); + } + } + + /* Releases */ + [data-component="releases"] { + display: flex; + flex-direction: column; + gap: 0; + } + + [data-component="release"] { + display: grid; + grid-template-columns: 180px 1fr; + gap: 3rem; + padding: 2rem 0; + border-bottom: 1px solid var(--color-border-weak); + + @media (max-width: 50rem) { + grid-template-columns: 1fr; + gap: 1rem; + } + + &:first-child { + padding-top: 0; + } + + &:last-child { + border-bottom: none; + } + + header { + display: flex; + flex-direction: column; + gap: 4px; + + @media (max-width: 50rem) { + flex-direction: row; + align-items: center; + gap: 12px; + } + + [data-slot="version"] { + a { + font-weight: 600; + color: var(--color-text-strong); + text-decoration: none; + + &:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + } + + time { + color: var(--color-text-weak); + font-size: 14px; + } + } + + [data-slot="content"] { + display: flex; + flex-direction: column; + gap: 1.5rem; + } + + [data-component="section"] { + h3 { + font-size: 14px; + font-weight: 600; + color: var(--color-text-strong); + margin-bottom: 8px; + } + + ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 6px; + + li { + color: var(--color-text); + line-height: 1.5; + padding-left: 16px; + position: relative; + + &::before { + content: "-"; + position: absolute; + left: 0; + color: var(--color-text-weak); + } + + [data-slot="author"] { + color: var(--color-text-weak); + font-size: 13px; + margin-left: 4px; + text-decoration: none; + + &:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + } + } + } + + [data-component="contributors"] { + font-size: 13px; + color: var(--color-text-weak); + padding-top: 0.5rem; + + span { + color: var(--color-text-weak); + } + + a { + color: var(--color-text); + text-decoration: none; + + &:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + } + } + + a { + color: var(--color-text-strong); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + + &:hover { + text-decoration-thickness: 2px; + } + } +} diff --git a/packages/console/app/src/routes/changelog/index.tsx b/packages/console/app/src/routes/changelog/index.tsx new file mode 100644 index 00000000000..cf71d021ccb --- /dev/null +++ b/packages/console/app/src/routes/changelog/index.tsx @@ -0,0 +1,147 @@ +import "./index.css" +import { Title, Meta, Link } from "@solidjs/meta" +import { createAsync, query } from "@solidjs/router" +import { Header } from "~/component/header" +import { Footer } from "~/component/footer" +import { Legal } from "~/component/legal" +import { config } from "~/config" +import { For, Show } from "solid-js" + +type Release = { + tag_name: string + name: string + body: string + published_at: string + html_url: string +} + +const getReleases = query(async () => { + "use server" + const response = await fetch("https://api.github.com/repos/anomalyco/opencode/releases?per_page=20", { + headers: { + Accept: "application/vnd.github.v3+json", + "User-Agent": "OpenCode-Console", + }, + cf: { + cacheTtl: 60 * 5, + cacheEverything: true, + }, + } as any) + if (!response.ok) return [] + return response.json() as Promise +}, "releases.get") + +function formatDate(dateString: string) { + const date = new Date(dateString) + return date.toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }) +} + +function parseMarkdown(body: string) { + const lines = body.split("\n") + const sections: { title: string; items: string[] }[] = [] + let current: { title: string; items: string[] } | null = null + let skip = false + + for (const line of lines) { + if (line.startsWith("## ")) { + if (current) sections.push(current) + const title = line.slice(3).trim() + current = { title, items: [] } + skip = false + } else if (line.startsWith("**Thank you")) { + skip = true + } else if (line.startsWith("- ") && !skip) { + current?.items.push(line.slice(2).trim()) + } + } + if (current) sections.push(current) + + return { sections } +} + +function ReleaseItem(props: { item: string }) { + const parts = () => { + const match = props.item.match(/^(.+?)(\s*\(@([\w-]+)\))?$/) + if (match) { + return { + text: match[1], + username: match[3], + } + } + return { text: props.item, username: undefined } + } + + return ( +
  • + {parts().text} + + + (@{parts().username}) + + +
  • + ) +} + +export default function Changelog() { + const releases = createAsync(() => getReleases()) + + return ( +
    + OpenCode | Changelog + + + +
    +
    + +
    +
    +

    Changelog

    +

    New updates and improvements to OpenCode

    +
    + +
    + + {(release) => { + const parsed = () => parseMarkdown(release.body || "") + return ( +
    +
    + + +
    +
    + + {(section) => ( +
    +

    {section.title}

    +
      + {(item) => } +
    +
    + )} +
    +
    +
    + ) + }} +
    +
    + +
    +
    +
    + + +
    + ) +} diff --git a/packages/console/app/src/routes/debug/index.ts b/packages/console/app/src/routes/debug/index.ts new file mode 100644 index 00000000000..2bdd269e781 --- /dev/null +++ b/packages/console/app/src/routes/debug/index.ts @@ -0,0 +1,13 @@ +import type { APIEvent } from "@solidjs/start/server" +import { json } from "@solidjs/router" +import { Database } from "@opencode-ai/console-core/drizzle/index.js" +import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" + +export async function GET(evt: APIEvent) { + return json({ + data: await Database.use(async (tx) => { + const result = await tx.$count(UserTable) + return result + }), + }) +} diff --git a/packages/console/app/src/routes/desktop-feedback.ts b/packages/console/app/src/routes/desktop-feedback.ts new file mode 100644 index 00000000000..1916cdb4cf7 --- /dev/null +++ b/packages/console/app/src/routes/desktop-feedback.ts @@ -0,0 +1,5 @@ +import { redirect } from "@solidjs/router" + +export async function GET() { + return redirect("https://discord.gg/h5TNnkFVNy") +} diff --git a/packages/console/app/src/routes/discord.ts b/packages/console/app/src/routes/discord.ts new file mode 100644 index 00000000000..7088295da5c --- /dev/null +++ b/packages/console/app/src/routes/discord.ts @@ -0,0 +1,5 @@ +import { redirect } from "@solidjs/router" + +export async function GET() { + return redirect("https://discord.gg/opencode") +} diff --git a/packages/console/app/src/routes/docs/[...path].ts b/packages/console/app/src/routes/docs/[...path].ts new file mode 100644 index 00000000000..f077815832a --- /dev/null +++ b/packages/console/app/src/routes/docs/[...path].ts @@ -0,0 +1,20 @@ +import type { APIEvent } from "@solidjs/start/server" + +async function handler(evt: APIEvent) { + const req = evt.request.clone() + const url = new URL(req.url) + const targetUrl = `https://docs.opencode.ai${url.pathname}${url.search}` + const response = await fetch(targetUrl, { + method: req.method, + headers: req.headers, + body: req.body, + }) + return response +} + +export const GET = handler +export const POST = handler +export const PUT = handler +export const DELETE = handler +export const OPTIONS = handler +export const PATCH = handler diff --git a/packages/console/app/src/routes/docs/index.ts b/packages/console/app/src/routes/docs/index.ts new file mode 100644 index 00000000000..f077815832a --- /dev/null +++ b/packages/console/app/src/routes/docs/index.ts @@ -0,0 +1,20 @@ +import type { APIEvent } from "@solidjs/start/server" + +async function handler(evt: APIEvent) { + const req = evt.request.clone() + const url = new URL(req.url) + const targetUrl = `https://docs.opencode.ai${url.pathname}${url.search}` + const response = await fetch(targetUrl, { + method: req.method, + headers: req.headers, + body: req.body, + }) + return response +} + +export const GET = handler +export const POST = handler +export const PUT = handler +export const DELETE = handler +export const OPTIONS = handler +export const PATCH = handler diff --git a/packages/console/app/src/routes/download/[platform].ts b/packages/console/app/src/routes/download/[platform].ts new file mode 100644 index 00000000000..2c30a803623 --- /dev/null +++ b/packages/console/app/src/routes/download/[platform].ts @@ -0,0 +1,38 @@ +import { APIEvent } from "@solidjs/start" +import { DownloadPlatform } from "./types" + +const assetNames: Record = { + "darwin-aarch64-dmg": "opencode-desktop-darwin-aarch64.dmg", + "darwin-x64-dmg": "opencode-desktop-darwin-x64.dmg", + "windows-x64-nsis": "opencode-desktop-windows-x64.exe", + "linux-x64-deb": "opencode-desktop-linux-amd64.deb", + "linux-x64-appimage": "opencode-desktop-linux-amd64.AppImage", + "linux-x64-rpm": "opencode-desktop-linux-x86_64.rpm", +} satisfies Record + +// Doing this on the server lets us preserve the original name for platforms we don't care to rename for +const downloadNames: Record = { + "darwin-aarch64-dmg": "OpenCode Desktop.dmg", + "darwin-x64-dmg": "OpenCode Desktop.dmg", + "windows-x64-nsis": "OpenCode Desktop Installer.exe", +} satisfies { [K in DownloadPlatform]?: string } + +export async function GET({ params: { platform } }: APIEvent) { + const assetName = assetNames[platform] + if (!assetName) return new Response("Not Found", { status: 404 }) + + const resp = await fetch(`https://github.com/anomalyco/opencode/releases/latest/download/${assetName}`, { + cf: { + // in case gh releases has rate limits + cacheTtl: 60 * 5, + cacheEverything: true, + }, + } as any) + + const downloadName = downloadNames[platform] + + const headers = new Headers(resp.headers) + if (downloadName) headers.set("content-disposition", `attachment; filename="${downloadName}"`) + + return new Response(resp.body, { ...resp, headers }) +} diff --git a/packages/console/app/src/routes/download/index.css b/packages/console/app/src/routes/download/index.css new file mode 100644 index 00000000000..a5ca692a2d5 --- /dev/null +++ b/packages/console/app/src/routes/download/index.css @@ -0,0 +1,750 @@ +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); + + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } +} + +[data-page="download"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-weak-hover: hsl(0, 8%, 94%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 60%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + --color-text-success: hsl(119, 100%, 35%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); + --color-success: hsl(142, 76%, 36%); + + background: var(--color-background); + font-family: var(--font-mono); + color: var(--color-text); + padding-bottom: 5rem; + + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-weak-hover: hsl(0, 6%, 15%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + --color-text-success: hsl(119, 60%, 72%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); + --color-success: hsl(142, 76%, 46%); + } + + /* Header and Footer styles - copied from enterprise */ + [data-component="top"] { + padding: 24px 5rem; + height: 80px; + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + z-index: 10; + + @media (max-width: 60rem) { + padding: 24px 1.5rem; + } + + img { + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + align-items: center; + gap: 48px; + + @media (max-width: 55rem) { + gap: 32px; + } + + @media (max-width: 48rem) { + gap: 24px; + } + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + [data-slot="cta-button"] { + background: var(--color-background-strong); + color: var(--color-text-inverted); + padding: 8px 16px; + border-radius: 4px; + font-weight: 500; + text-decoration: none; + + @media (max-width: 55rem) { + display: none; + } + } + [data-slot="cta-button"]:hover { + background: var(--color-background-strong-hover); + text-decoration: none; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile"] { + button > svg { + color: var(--color-icon); + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + margin-right: -8px; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + flex-direction: row; + + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + [data-slot="cell"] { + flex: 1; + text-align: center; + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + + [data-slot="cell"] + [data-slot="cell"] { + border-left: 1px solid var(--color-border-weak); + + @media (max-width: 40rem) { + border-left: none; + } + } + + @media (max-width: 25rem) { + flex-wrap: wrap; + + [data-slot="cell"] { + flex: 1 0 100%; + border-left: none; + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; + } + } + } + + [data-component="container"] { + max-width: 67.5rem; + margin: 0 auto; + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { + padding: 6rem 5rem; + + @media (max-width: 60rem) { + padding: 4rem 1.5rem; + } + } + + [data-component="legal"] { + color: var(--color-text-weak); + text-align: center; + padding: 2rem 5rem; + display: flex; + gap: 32px; + justify-content: center; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + a { + color: var(--color-text-weak); + text-decoration: none; + } + + a:hover { + color: var(--color-text); + text-decoration: underline; + } + } + + /* Download Hero Section */ + [data-component="download-hero"] { + display: grid; + grid-template-columns: 260px 1fr; + gap: 4rem; + padding-bottom: 2rem; + margin-bottom: 4rem; + + @media (max-width: 50rem) { + grid-template-columns: 1fr; + gap: 1.5rem; + padding-bottom: 2rem; + margin-bottom: 2rem; + } + + [data-component="hero-icon"] { + display: flex; + justify-content: flex-end; + align-items: center; + + @media (max-width: 40rem) { + display: none; + } + + [data-slot="icon-placeholder"] { + width: 120px; + height: 120px; + background: var(--color-background-weak); + border: 1px solid var(--color-border-weak); + border-radius: 24px; + + @media (max-width: 50rem) { + width: 80px; + height: 80px; + } + } + + img { + width: 120px; + height: 120px; + border-radius: 24px; + box-shadow: + 0 1.467px 2.847px 0 rgba(0, 0, 0, 0.42), + 0 0.779px 1.512px 0 rgba(0, 0, 0, 0.34), + 0 0.324px 0.629px 0 rgba(0, 0, 0, 0.24); + + @media (max-width: 50rem) { + width: 80px; + height: 80px; + border-radius: 16px; + } + } + + @media (max-width: 50rem) { + justify-content: flex-start; + } + } + + [data-component="hero-text"] { + display: flex; + flex-direction: column; + justify-content: center; + + h1 { + font-size: 1.5rem; + font-weight: 700; + color: var(--color-text-strong); + margin-bottom: 4px; + + @media (max-width: 40rem) { + margin-bottom: 1rem; + } + } + + p { + color: var(--color-text); + margin-bottom: 12px; + + @media (max-width: 40rem) { + margin-bottom: 2.5rem; + line-height: 1.6; + } + } + + [data-component="download-button"] { + padding: 8px 20px 8px 16px; + background: var(--color-background-strong); + color: var(--color-text-inverted); + border: none; + border-radius: 4px; + font-weight: 500; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 10px; + transition: all 0.2s ease; + text-decoration: none; + width: fit-content; + + &:hover:not(:disabled) { + background: var(--color-background-strong-hover); + } + + &:active { + transform: scale(0.98); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + } + } + + /* Download Sections */ + [data-component="download-section"] { + display: grid; + grid-template-columns: 260px 1fr; + gap: 4rem; + margin-bottom: 4rem; + + @media (max-width: 50rem) { + grid-template-columns: 1fr; + gap: 1rem; + margin-bottom: 3rem; + } + + &:last-child { + margin-bottom: 0; + } + + [data-component="section-label"] { + font-weight: 500; + color: var(--color-text-strong); + padding-top: 1rem; + + span { + color: var(--color-text-weaker); + } + + @media (max-width: 50rem) { + padding-top: 0; + padding-bottom: 0.5rem; + } + } + + [data-component="section-content"] { + display: flex; + flex-direction: column; + gap: 0; + } + } + + /* CLI Rows */ + button[data-component="cli-row"] { + display: flex; + align-items: center; + gap: 12px; + padding: 1rem 0.5rem 1rem 1.5rem; + margin: 0 -0.5rem 0 -1.5rem; + background: none; + border: none; + border-radius: 4px; + width: calc(100% + 2rem); + text-align: left; + cursor: pointer; + transition: background 0.15s ease; + + &:hover { + background: var(--color-background-weak); + } + + code { + font-family: var(--font-mono); + color: var(--color-text-weak); + + strong { + color: var(--color-text-strong); + font-weight: 500; + } + } + + [data-component="copy-status"] { + display: flex; + align-items: center; + opacity: 0; + transition: opacity 0.15s ease; + color: var(--color-icon); + + svg { + width: 18px; + height: 18px; + } + + [data-slot="copy"] { + display: block; + } + + [data-slot="check"] { + display: none; + } + } + + &:hover [data-component="copy-status"] { + opacity: 1; + } + + &[data-copied] [data-component="copy-status"] { + opacity: 1; + + [data-slot="copy"] { + display: none; + } + + [data-slot="check"] { + display: block; + } + } + } + + /* Download Rows */ + [data-component="download-row"] { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 0.5rem 0.75rem 1.5rem; + margin: 0 -0.5rem 0 -1.5rem; + border-radius: 4px; + transition: background 0.15s ease; + + &:hover { + background: var(--color-background-weak); + } + + [data-component="download-info"] { + display: flex; + align-items: center; + gap: 0.75rem; + + [data-slot="icon"] { + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + color: var(--color-icon); + + svg { + width: 20px; + height: 20px; + } + + img { + width: 20px; + height: 20px; + } + } + + span { + color: var(--color-text); + } + } + + [data-component="action-button"] { + padding: 6px 16px; + background: var(--color-background); + color: var(--color-text); + border: 1px solid var(--color-border); + border-radius: 4px; + font-weight: 500; + cursor: pointer; + text-decoration: none; + transition: all 0.2s ease; + + &:hover { + background: var(--color-background-weak); + border-color: var(--color-border); + text-decoration: none; + } + + &:active { + transform: scale(0.98); + } + } + } + + a { + color: var(--color-text-strong); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + + &:hover { + text-decoration-thickness: 2px; + } + } + + /* Narrow screen font sizes */ + @media (max-width: 40rem) { + [data-component="download-section"] { + [data-component="section-label"] { + font-size: 14px; + } + } + + button[data-component="cli-row"] { + margin: 0; + padding: 1rem 0; + width: 100%; + overflow: hidden; + + code { + font-size: 14px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: block; + max-width: calc(100vw - 80px); + } + + [data-component="copy-status"] { + opacity: 1 !important; + flex-shrink: 0; + } + } + + [data-component="download-row"] { + margin: 0; + padding: 0.75rem 0; + + [data-component="download-info"] span { + font-size: 14px; + } + + [data-component="action-button"] { + font-size: 14px; + padding-left: 8px; + padding-right: 8px; + } + } + } + + @media (max-width: 22.5rem) { + [data-slot="hide-narrow"] { + display: none; + } + } + + /* FAQ Section */ + [data-component="faq"] { + border-top: 1px solid var(--color-border-weak); + padding: 4rem 5rem; + margin-top: 4rem; + + @media (max-width: 60rem) { + padding: 3rem 1.5rem; + margin-top: 3rem; + } + + [data-slot="section-title"] { + margin-bottom: 24px; + + h3 { + font-size: 16px; + font-weight: 700; + color: var(--color-text-strong); + margin-bottom: 12px; + } + } + + ul { + padding: 0; + + li { + list-style: none; + margin-bottom: 24px; + line-height: 200%; + } + } + + [data-slot="faq-question"] { + display: flex; + gap: 16px; + margin-bottom: 8px; + color: var(--color-text-strong); + font-weight: 500; + cursor: pointer; + background: none; + border: none; + padding: 0; + align-items: start; + min-height: 24px; + + svg { + margin-top: 2px; + } + + [data-slot="faq-icon-plus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: none; + } + [data-expanded] & { + display: block; + } + } + [data-slot="faq-question-text"] { + flex-grow: 1; + text-align: left; + } + } + + [data-slot="faq-answer"] { + margin-left: 40px; + margin-bottom: 32px; + line-height: 200%; + } + } +} diff --git a/packages/console/app/src/routes/download/index.tsx b/packages/console/app/src/routes/download/index.tsx new file mode 100644 index 00000000000..8b8f50968ce --- /dev/null +++ b/packages/console/app/src/routes/download/index.tsx @@ -0,0 +1,482 @@ +import "./index.css" +import { Title, Meta, Link } from "@solidjs/meta" +import { A, createAsync, query } from "@solidjs/router" +import { Header } from "~/component/header" +import { Footer } from "~/component/footer" +import { IconCopy, IconCheck } from "~/component/icon" +import { Faq } from "~/component/faq" +import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png" +import { Legal } from "~/component/legal" +import { config } from "~/config" +import { createSignal, onMount, Show, JSX } from "solid-js" +import { DownloadPlatform } from "./types" + +type OS = "macOS" | "Windows" | "Linux" | null + +function detectOS(): OS { + if (typeof navigator === "undefined") return null + const platform = navigator.platform.toLowerCase() + const userAgent = navigator.userAgent.toLowerCase() + + if (platform.includes("mac") || userAgent.includes("mac")) return "macOS" + if (platform.includes("win") || userAgent.includes("win")) return "Windows" + if (platform.includes("linux") || userAgent.includes("linux")) return "Linux" + return null +} + +function getDownloadPlatform(os: OS): DownloadPlatform { + switch (os) { + case "macOS": + return "darwin-aarch64-dmg" + case "Windows": + return "windows-x64-nsis" + case "Linux": + return "linux-x64-deb" + default: + return "darwin-aarch64-dmg" + } +} + +function getDownloadHref(platform: DownloadPlatform) { + return `/download/${platform}` +} + +function IconDownload(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} + +function CopyStatus() { + return ( + + + + + ) +} + +export default function Download() { + const [detectedOS, setDetectedOS] = createSignal(null) + + onMount(() => { + setDetectedOS(detectOS()) + }) + + const handleCopyClick = (command: string) => (event: Event) => { + const button = event.currentTarget as HTMLButtonElement + navigator.clipboard.writeText(command) + button.setAttribute("data-copied", "") + setTimeout(() => { + button.removeAttribute("data-copied") + }, 1500) + } + return ( +
    + OpenCode | Download + + +
    +
    + +
    +
    +
    + OpenCode Desktop +
    +
    +

    Download OpenCode

    +

    Available in Beta for macOS, Windows, and Linux

    + + + + Download for {detectedOS()} + + +
    +
    + +
    +
    + [1] OpenCode Terminal +
    +
    + + + + + +
    +
    + +
    +
    + [2] OpenCode Desktop (Beta) +
    +
    + +
    +
    + + + + + + + macOS (Apple Silicon) + +
    + + Download + +
    +
    +
    + + + + + + macOS (Intel) +
    + + Download + +
    +
    +
    + + + + + + + + + + + + + Windows (x64) +
    + + Download + +
    +
    +
    + + + + + + Linux (.deb) +
    + + Download + +
    +
    +
    + + + + + + Linux (.rpm) +
    + + Download + +
    + {/* Disabled temporarily as it doesn't work */} + {/*
    +
    + + + + + + Linux (.AppImage) +
    + + Download + +
    */} +
    +
    + +
    +
    + [3] OpenCode Extensions +
    +
    +
    +
    + + + + + + + + + + + + + VS Code +
    + + Install + +
    + +
    +
    + + + + + + + + + + + + + Cursor +
    + + Install + +
    + +
    +
    + + + + + + Zed +
    + + Install + +
    + +
    +
    + + + + + + Windsurf +
    + + Install + +
    + +
    +
    + + + + + + VSCodium +
    + + Install + +
    +
    +
    + +
    +
    + [4] OpenCode Integrations +
    +
    +
    +
    + + + + + + GitHub +
    + + Install + +
    + +
    +
    + + + + + + GitLab +
    + + Install + +
    +
    +
    +
    + +
    +
    +

    FAQ

    +
    +
      +
    • + + OpenCode is an open source agent that helps you write and run code with any AI model. It's available as + a terminal-based interface, desktop app, or IDE extension. + +
    • +
    • + + The easiest way to get started is to read the intro. + +
    • +
    • + + Not necessarily, but probably. You'll need an AI subscription if you want to connect OpenCode to a paid + provider, although you can work with{" "} + + local models + {" "} + for free. While we encourage users to use Zen, OpenCode works with all popular + providers such as OpenAI, Anthropic, xAI etc. + +
    • +
    • + + Not anymore! OpenCode is now available as an app for your desktop and{" "} + web! + +
    • +
    • + + OpenCode is 100% free to use. Any additional costs will come from your subscription to a model provider. + While OpenCode works with any model provider, we recommend using Zen. + +
    • +
    • + + Your data and information is only stored when you create sharable links in OpenCode. Learn more about{" "} + share pages. + +
    • +
    • + + Yes, OpenCode is fully open source. The source code is public on{" "} + + GitHub + {" "} + under the{" "} + + MIT License + + , meaning anyone can use, modify, or contribute to its development. Anyone from the community can file + issues, submit pull requests, and extend functionality. + +
    • +
    +
    + +
    +
    + +
    + ) +} diff --git a/packages/console/app/src/routes/download/types.ts b/packages/console/app/src/routes/download/types.ts new file mode 100644 index 00000000000..916f97022e3 --- /dev/null +++ b/packages/console/app/src/routes/download/types.ts @@ -0,0 +1,4 @@ +export type DownloadPlatform = + | `darwin-${"x64" | "aarch64"}-dmg` + | "windows-x64-nsis" + | `linux-x64-${"deb" | "rpm" | "appimage"}` diff --git a/packages/console/app/src/routes/enterprise/index.css b/packages/console/app/src/routes/enterprise/index.css new file mode 100644 index 00000000000..7eebf16ce98 --- /dev/null +++ b/packages/console/app/src/routes/enterprise/index.css @@ -0,0 +1,578 @@ +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); + + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } +} + +[data-page="enterprise"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-weak-hover: hsl(0, 8%, 94%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 60%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + --color-text-success: hsl(119, 100%, 35%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); + --color-success: hsl(142, 76%, 36%); + + background: var(--color-background); + font-family: var(--font-mono); + color: var(--color-text); + padding-bottom: 5rem; + + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-weak-hover: hsl(0, 6%, 15%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + --color-text-success: hsl(119, 60%, 72%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); + --color-success: hsl(142, 76%, 46%); + } + + /* Header and Footer styles - copied from index.css */ + [data-component="top"] { + padding: 24px 5rem; + height: 80px; + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + z-index: 10; + + @media (max-width: 60rem) { + padding: 24px 1.5rem; + } + + img { + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + align-items: center; + gap: 48px; + + @media (max-width: 55rem) { + gap: 32px; + } + + @media (max-width: 48rem) { + gap: 24px; + } + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + [data-slot="cta-button"] { + background: var(--color-background-strong); + color: var(--color-text-inverted); + padding: 8px 16px 8px 10px; + border-radius: 4px; + font-weight: 500; + text-decoration: none; + display: flex; + align-items: center; + gap: 8px; + + @media (max-width: 55rem) { + display: none; + } + } + [data-slot="cta-button"]:hover { + background: var(--color-background-strong-hover); + text-decoration: none; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile"] { + button > svg { + color: var(--color-icon); + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + margin-right: -8px; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + flex-direction: row; + + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + [data-slot="cell"] { + flex: 1; + text-align: center; + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + + [data-slot="cell"] + [data-slot="cell"] { + border-left: 1px solid var(--color-border-weak); + + @media (max-width: 40rem) { + border-left: none; + } + } + + /* Mobile: third column on its own row */ + @media (max-width: 25rem) { + flex-wrap: wrap; + + [data-slot="cell"] { + flex: 1 0 100%; + border-left: none; + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; + } + } + } + + [data-component="container"] { + max-width: 67.5rem; + margin: 0 auto; + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { + } + + [data-component="enterprise-content"] { + padding: 4rem 0; + + @media (max-width: 60rem) { + padding: 2rem 0; + } + } + + [data-component="enterprise-columns"] { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; + padding: 4rem 5rem; + + @media (max-width: 80rem) { + gap: 3rem; + } + + @media (max-width: 60rem) { + grid-template-columns: 1fr; + gap: 3rem; + padding: 2rem 1.5rem; + } + } + + [data-component="enterprise-column-1"] { + h1 { + font-size: 1.5rem; + font-weight: 700; + color: var(--color-text-strong); + margin-bottom: 1rem; + } + + h3 { + font-size: 1.25rem; + font-weight: 500; + color: var(--color-text-strong); + margin: 2rem 0 1rem 0; + } + + p { + line-height: 1.6; + margin-bottom: 1.5rem; + color: var(--color-text); + } + + [data-component="testimonial"] { + margin-top: 4rem; + font-weight: 500; + color: var(--color-text-strong); + + [data-component="quotation"] { + svg { + margin-bottom: 1rem; + opacity: 20%; + } + } + + [data-component="testimonial-logo"] { + svg { + margin-top: 1.5rem; + } + } + } + } + + [data-component="enterprise-column-2"] { + [data-component="enterprise-form"] { + padding: 0; + + h2 { + font-size: 1.5rem; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 1.5rem; + } + + [data-component="form-group"] { + margin-bottom: 1.5rem; + + label { + display: block; + font-weight: 500; + color: var(--color-text-weak); + margin-bottom: 0.5rem; + font-size: 0.875rem; + } + + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + transition: background-color 5000000s ease-in-out 0s; + } + + input:-webkit-autofill { + -webkit-text-fill-color: var(--color-text-strong) !important; + } + + input:-moz-autofill { + -moz-text-fill-color: var(--color-text-strong) !important; + } + + input, + textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid var(--color-border-weak); + border-radius: 4px; + background: var(--color-background-weak); + color: var(--color-text-strong); + font-family: inherit; + + &::placeholder { + color: var(--color-text-weak); + } + + &:focus { + background: var(--color-background-interactive-weaker); + outline: none; + border: none; + color: var(--color-text-strong); + border: 1px solid var(--color-background-strong); + box-shadow: 0 0 0 3px var(--color-background-interactive); + + @media (prefers-color-scheme: dark) { + box-shadow: none; + border: 1px solid var(--color-background-interactive); + } + } + } + + textarea { + resize: vertical; + min-height: 120px; + } + } + + [data-component="submit-button"] { + padding: 0.5rem 1.5rem; + background: var(--color-background-strong); + color: var(--color-text-inverted); + border: none; + border-radius: 4px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s ease; + + &:hover:not(:disabled) { + background: var(--color-background-strong-hover); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + [data-component="success-message"] { + margin-top: 1rem; + padding: 1rem 0; + color: var(--color-text-success); + text-align: left; + } + } + } + + [data-component="faq"] { + border-top: 1px solid var(--color-border-weak); + padding: 4rem 5rem; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + [data-slot="section-title"] { + margin-bottom: 24px; + + h3 { + font-size: 16px; + font-weight: 700; + color: var(--color-text-strong); + margin-bottom: 12px; + } + + p { + margin-bottom: 12px; + color: var(--color-text); + } + } + + ul { + padding: 0; + + li { + list-style: none; + margin-bottom: 24px; + line-height: 200%; + + @media (max-width: 60rem) { + line-height: 180%; + } + } + } + + [data-slot="faq-question"] { + display: flex; + gap: 16px; + margin-bottom: 8px; + color: var(--color-text-strong); + font-weight: 500; + cursor: pointer; + background: none; + border: none; + padding: 0; + + [data-slot="faq-icon-plus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: none; + } + [data-expanded] & { + display: block; + } + } + [data-slot="faq-question-text"] { + flex-grow: 1; + text-align: left; + } + } + + [data-slot="faq-answer"] { + margin-left: 40px; + margin-bottom: 32px; + color: var(--color-text); + } + } + + [data-component="legal"] { + color: var(--color-text-weak); + text-align: center; + padding: 2rem 5rem; + display: flex; + gap: 32px; + justify-content: center; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + a { + color: var(--color-text-weak); + text-decoration: none; + } + + a:hover { + color: var(--color-text); + text-decoration: underline; + } + } + + a { + color: var(--color-text-strong); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + + &:hover { + text-decoration-thickness: 2px; + } + } +} diff --git a/packages/console/app/src/routes/enterprise/index.tsx b/packages/console/app/src/routes/enterprise/index.tsx new file mode 100644 index 00000000000..095ed97a2ff --- /dev/null +++ b/packages/console/app/src/routes/enterprise/index.tsx @@ -0,0 +1,251 @@ +import "./index.css" +import { Title, Meta, Link } from "@solidjs/meta" +import { createSignal, Show } from "solid-js" +import { config } from "~/config" +import { Header } from "~/component/header" +import { Footer } from "~/component/footer" +import { Legal } from "~/component/legal" +import { Faq } from "~/component/faq" + +export default function Enterprise() { + const [formData, setFormData] = createSignal({ + name: "", + role: "", + email: "", + message: "", + }) + const [isSubmitting, setIsSubmitting] = createSignal(false) + const [showSuccess, setShowSuccess] = createSignal(false) + + const handleInputChange = (field: string) => (e: Event) => { + const target = e.target as HTMLInputElement | HTMLTextAreaElement + setFormData((prev) => ({ ...prev, [field]: target.value })) + } + + const handleSubmit = async (e: Event) => { + e.preventDefault() + setIsSubmitting(true) + + try { + const response = await fetch("/api/enterprise", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData()), + }) + + if (response.ok) { + setShowSuccess(true) + setFormData({ + name: "", + role: "", + email: "", + message: "", + }) + setTimeout(() => setShowSuccess(false), 5000) + } + } catch (error) { + console.error("Failed to submit form:", error) + } finally { + setIsSubmitting(false) + } + } + + return ( +
    + OpenCode | Enterprise solutions for your organisation + + +
    +
    + +
    +
    +
    +
    +

    Your code is yours

    +

    + OpenCode operates securely inside your organization with no data or context stored and no licensing + restrictions or ownership claims. Start a trial with your team, then deploy it across your + organization by integrating it with your SSO and internal AI gateway. +

    +

    Let us know and how we can help.

    + + +
    +
    + + + +
    + Thanks to OpenCode, we found a way to create software to track all our assets — even the imaginary + ones. +
    + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +