diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..a9d0ab3ca13 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,39 @@ +# Git +.git + +# IDE +.idea +.vscode +*.swp +*~ + +# Build artifacts (we build fresh in Docker) +node_modules +dist +ts-dist +.turbo +target + +# Development files +.DS_Store +.opencode +.worktrees +.sst +.env +playground +tmp +.serena +refs +Session.vim +opencode.json +a.out +.scripts + +# Documentation (not needed for build) +docs/ +CONTEXT/ +specs/ +logs/ + +# Tauri (native desktop app - not needed for Docker) +packages/desktop/src-tauri/target diff --git a/.github/ISSUE_TEMPLATE/upstream-sync-conflict.md b/.github/ISSUE_TEMPLATE/upstream-sync-conflict.md new file mode 100644 index 00000000000..5a61d71e995 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/upstream-sync-conflict.md @@ -0,0 +1,70 @@ +--- +name: Upstream Sync Conflict +about: Automatically created when upstream sync encounters conflicts +title: "[Upstream Sync] Merge conflict with {{ tag }}" +labels: upstream-sync, needs-manual-review +assignees: "" +--- + +## Upstream Sync Conflict Report + +**Trigger**: Upstream sync at {{ timestamp }} +**Upstream Tag**: {{ tag }} +**Upstream SHA**: {{ upstream_sha }} +**Integration SHA**: {{ integration_sha }} + +### Conflicting Files + +{{ conflict_list }} + +### Recommended Actions + +1. Checkout integration branch locally +2. Run: `git fetch origin && git merge origin/dev` +3. Resolve conflicts manually +4. Run validation: + ```bash + bun install + bun turbo typecheck + bun turbo test + ``` +5. Push resolved integration branch +6. Close this issue + +### Resolution Strategies + +| File Pattern | Resolution Strategy | +| ------------------------------- | ----------------------------------------------- | +| `bun.lock` | Regenerate from merged manifest: `bun install` | +| `*.md` (docs) | Accept upstream: `git checkout --theirs ` | +| `package.json` | Manual review required | +| `.github/*` (workflow configs) | Keep ours: `git checkout --ours ` | +| Shared code with custom changes | Manual review required | + +### Manual Sync Commands + +```bash +git fetch origin +git checkout integration +git merge origin/dev + +# Resolve conflicts... + +bun install +bun turbo typecheck +bun turbo test +bun turbo build + +git add . +git commit -m "sync: resolve conflicts with {{ tag }}" +git push origin integration +``` + +### Logs + +
+Merge output + +{{ merge_output }} + +
diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index cba04faccef..2c4e04ef5e9 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -3,6 +3,11 @@ description: "Setup Bun with caching and install dependencies" runs: using: "composite" steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + - name: Setup Bun uses: oven-sh/setup-bun@v2 with: diff --git a/.github/last-synced-tag b/.github/last-synced-tag new file mode 100644 index 00000000000..c641220244f --- /dev/null +++ b/.github/last-synced-tag @@ -0,0 +1 @@ +v1.1.4 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 25466a63e06..00000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: deploy - -on: - push: - branches: - - dev - - production - workflow_dispatch: - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -jobs: - deploy: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - - - uses: ./.github/actions/setup-bun - - - 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 deleted file mode 100644 index a8dd2ae4f2b..00000000000 --- a/.github/workflows/docs-update.yml +++ /dev/null @@ -1,72 +0,0 @@ -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 deleted file mode 100644 index 53aa2a725eb..00000000000 --- a/.github/workflows/duplicate-issues.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Duplicate Issue Detection - -on: - issues: - types: [opened] - -jobs: - check-duplicates: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - issues: write - 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: Check for duplicate issues - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENCODE_PERMISSION: | - { - "bash": { - "*": "deny", - "gh issue*": "allow" - }, - "webfetch": "deny" - } - run: | - opencode run -m opencode/claude-haiku-4-5 "A new issue has been created:' - - Issue number: - ${{ github.event.issue.number }} - - Lookup this issue and search through existing issues (excluding #${{ github.event.issue.number }}) in this repository to find any potential duplicates of this new issue. - Consider: - 1. Similar titles or descriptions - 2. Same error messages or symptoms - 3. Related functionality or components - 4. Similar feature requests - - If you find any potential duplicates, please comment on the new issue with: - - A brief explanation of why it might be a duplicate - - Links to the potentially duplicate issues - - A suggestion to check those issues first - - Use this format for the comment: - 'This issue might be a duplicate of existing issues. Please check: - - #[issue_number]: [brief description of similarity] - - 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/generate.yml b/.github/workflows/generate.yml deleted file mode 100644 index 29cc9895393..00000000000 --- a/.github/workflows/generate.yml +++ /dev/null @@ -1,51 +0,0 @@ -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/notify-discord.yml b/.github/workflows/notify-discord.yml deleted file mode 100644 index 62577ecf00e..00000000000 --- a/.github/workflows/notify-discord.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: discord - -on: - release: - types: [released] # fires when a draft release is published - -jobs: - notify: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - name: Send nicely-formatted embed to Discord - uses: SethCohen/github-releases-to-discord@v1 - with: - webhook_url: ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml index 76e75fcaefb..646b9c92007 100644 --- a/.github/workflows/opencode.yml +++ b/.github/workflows/opencode.yml @@ -1,4 +1,4 @@ -name: opencode +name: shuvcode on: issue_comment: @@ -7,28 +7,36 @@ on: types: [created] jobs: - opencode: + shuvcode: if: | - contains(github.event.comment.body, ' /oc') || - startsWith(github.event.comment.body, '/oc') || - contains(github.event.comment.body, ' /opencode') || - startsWith(github.event.comment.body, '/opencode') + contains(github.event.comment.body, '/shuv') || + contains(github.event.comment.body, '/shuvcode') || + contains(github.event.comment.body, '/oc') || + contains(github.event.comment.body, '/opencode') runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: id-token: write - contents: read - pull-requests: read - issues: read + contents: write + pull-requests: write + issues: write steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Checkout integration branch for upstream-sync issues (non-PR issues) + - name: Checkout integration branch for sync issues + if: ${{ !github.event.issue.pull_request && contains(github.event.issue.labels.*.name, 'upstream-sync') }} + run: git checkout integration - uses: ./.github/actions/setup-bun - - name: Run opencode - uses: anomalyco/opencode/github@latest + - name: Run shuvcode + uses: Latitudes-Dev/shuvcode/github@integration env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - OPENCODE_PERMISSION: '{"bash": "deny"}' + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} + OPENCODE_PERMISSION: '{"external_directory": "allow"}' with: - model: opencode/claude-opus-4-5 + model: anthropic/claude-opus-4-5 diff --git a/.github/workflows/publish-github-action.yml b/.github/workflows/publish-github-action.yml deleted file mode 100644 index d2789373a34..00000000000 --- a/.github/workflows/publish-github-action.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: publish-github-action - -on: - workflow_dispatch: - push: - tags: - - "github-v*.*.*" - - "!github-v1" - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -permissions: - contents: write - -jobs: - publish: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - run: git fetch --force --tags - - - name: Publish - run: | - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" - ./script/publish - working-directory: ./github diff --git a/.github/workflows/publish-vscode.yml b/.github/workflows/publish-vscode.yml deleted file mode 100644 index f49a1057807..00000000000 --- a/.github/workflows/publish-vscode.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: publish-vscode - -on: - workflow_dispatch: - push: - tags: - - "vscode-v*.*.*" - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -permissions: - contents: write - -jobs: - publish: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - 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: | - ./script/publish - working-directory: ./sdks/vscode - env: - VSCE_PAT: ${{ secrets.VSCE_PAT }} - OPENVSX_TOKEN: ${{ secrets.OPENVSX_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5720996170e..c7c36c2dd99 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,10 +2,6 @@ name: publish run-name: "${{ format('release {0}', inputs.bump) }}" on: - push: - branches: - - dev - - snapshot-* workflow_dispatch: inputs: bump: @@ -31,7 +27,7 @@ permissions: jobs: publish: runs-on: blacksmith-4vcpu-ubuntu-2404 - if: github.repository == 'anomalyco/opencode' + if: github.repository == 'Latitudes-Dev/shuvcode' steps: - uses: actions/checkout@v3 with: @@ -65,9 +61,9 @@ jobs: - 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 }} + git config --global user.email "shuvcode@latitudes.dev" + git config --global user.name "shuvcode" + git remote set-url origin https://x-access-token:${{ secrets.PAT_TOKEN }}@github.com/${{ github.repository }} - name: Publish id: publish @@ -77,7 +73,9 @@ jobs: OPENCODE_VERSION: ${{ inputs.version }} OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} AUR_KEY: ${{ secrets.AUR_KEY }} - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} + GH_TOKEN: ${{ secrets.PAT_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_CONFIG_PROVENANCE: false - uses: actions/upload-artifact@v4 @@ -161,7 +159,7 @@ jobs: env: OPENCODE_VERSION: ${{ needs.publish.outputs.version }} NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} AUR_KEY: ${{ secrets.AUR_KEY }} OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} RUST_TARGET: ${{ matrix.settings.target }} @@ -222,12 +220,12 @@ jobs: 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" + git config --global user.email "shuvcode@latitudes.dev" + git config --global user.name "shuvcode" ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true - run: ./script/publish-complete.ts env: OPENCODE_VERSION: ${{ needs.publish.outputs.version }} AUR_KEY: ${{ secrets.AUR_KEY }} - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} diff --git a/.github/workflows/release-github-action.yml b/.github/workflows/release-github-action.yml index 3f5caa55c8d..457b0fb95fb 100644 --- a/.github/workflows/release-github-action.yml +++ b/.github/workflows/release-github-action.yml @@ -1,11 +1,12 @@ name: release-github-action on: - push: - branches: - - dev - paths: - - "github/**" + workflow_dispatch: +# push: +# branches: +# - integration +# paths: +# - "github/**" concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -24,6 +25,6 @@ jobs: - name: Release run: | - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" + git config --global user.email "shuvcode@latitudes.dev" + git config --global user.name "shuvcode" ./github/script/release diff --git a/.github/workflows/release-vscode-extension.yml b/.github/workflows/release-vscode-extension.yml new file mode 100644 index 00000000000..e0ada7f2ea2 --- /dev/null +++ b/.github/workflows/release-vscode-extension.yml @@ -0,0 +1,91 @@ +name: release-vscode-extension + +on: + workflow_dispatch: + inputs: + minor: + description: "Bump minor version (resets patch to 0)" + required: false + type: boolean + default: false + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + +jobs: + release: + runs-on: blacksmith-4vcpu-ubuntu-2404 + if: github.repository == 'Latitudes-Dev/shuvcode' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: git fetch --force --tags + + - uses: ./.github/actions/setup-bun + + - name: Setup Git Identity + run: | + git config --global user.email "shuvcode@latitudes.dev" + git config --global user.name "shuvcode" + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + + - name: Create Release Tag + id: release + working-directory: sdks/vscode + run: | + if [ "${{ inputs.minor }}" = "true" ]; then + ./script/release --minor + else + ./script/release + fi + + # Get the new tag + latest_tag=$(git tag --sort=committerdate | grep -E '^vscode-v[0-9]+\.[0-9]+\.[0-9]+$' | tail -1) + echo "tag=$latest_tag" >> $GITHUB_OUTPUT + version=$(echo "$latest_tag" | sed 's/^vscode-v//') + echo "version=$version" >> $GITHUB_OUTPUT + + - name: Install VS Code Extension Dependencies + working-directory: sdks/vscode + run: bun install + + - name: Build Extension + working-directory: sdks/vscode + run: bun run package + + - name: Package VSIX + working-directory: sdks/vscode + run: | + mkdir -p dist + npx @vscode/vsce package --no-git-tag-version --no-update-package-json --no-dependencies --skip-license -o "dist/shuvcode-${{ steps.release.outputs.version }}.vsix" "${{ steps.release.outputs.version }}" + + - name: Create GitHub Release + run: | + # Create release if it doesn't exist + if ! gh release view ${{ steps.release.outputs.tag }} --repo ${{ github.repository }} > /dev/null 2>&1; then + gh release create ${{ steps.release.outputs.tag }} \ + --repo ${{ github.repository }} \ + --title "VS Code Extension ${{ steps.release.outputs.version }}" \ + --notes "shuvcode VS Code Extension v${{ steps.release.outputs.version }}" + fi + + # Upload VSIX asset + gh release upload ${{ steps.release.outputs.tag }} \ + sdks/vscode/dist/shuvcode-${{ steps.release.outputs.version }}.vsix \ + --repo ${{ github.repository }} \ + --clobber + env: + GH_TOKEN: ${{ github.token }} + + - name: Summary + run: | + echo "## VS Code Extension Released" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Tag:** ${{ steps.release.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "**Version:** ${{ steps.release.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Download:** https://github.com/${{ github.repository }}/releases/tag/${{ steps.release.outputs.tag }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index 93b01bafa2b..e469a71df4b 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -8,7 +8,9 @@ jobs: check-guidelines: if: | github.event.issue.pull_request && - startsWith(github.event.comment.body, '/review') && + (startsWith(github.event.comment.body, '/review') || + startsWith(github.event.comment.body, '/shuv') || + startsWith(github.event.comment.body, '/shuvcode')) && contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association) runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: @@ -31,8 +33,10 @@ jobs: - uses: ./.github/actions/setup-bun - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash + - name: Install shuvcode + run: | + # Install shuvcode from fork releases + curl -fsSL https://raw.githubusercontent.com/Latitudes-Dev/shuvcode/integration/install | bash - name: Get PR details id: pr-details @@ -51,7 +55,7 @@ jobs: 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}' + shuvcode run -m anthropic/claude-opus-4-5 "A new pull request has been created: '${PR_TITLE}' ${{ steps.pr-number.outputs.number }} diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 00000000000..514a3d2a7b0 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,97 @@ +name: snapshot + +on: + workflow_dispatch: + workflow_run: + workflows: ["test"] + types: + - completed + branches: + - integration + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + id-token: write + +jobs: + publish: + runs-on: blacksmith-4vcpu-ubuntu-2404 + # Only run if tests passed (workflow_run) or manual dispatch + # Also skip release commits to prevent infinite loop + if: | + (github.event_name == 'workflow_dispatch') || + (github.event_name == 'workflow_run' && + github.event.workflow_run.conclusion == 'success' && + !startsWith(github.event.workflow_run.head_commit.message, 'release:') && + !startsWith(github.event.workflow_run.head_commit.message, 'chore:')) + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.PAT_TOKEN }} + # Checkout the branch by name so git branch --show-current works + # For workflow_run, use head_branch; for workflow_dispatch, use ref + ref: ${{ github.event.workflow_run.head_branch || github.ref }} + + - run: git fetch --force --tags + + - uses: actions/setup-go@v5 + with: + go-version: ">=1.24.0" + cache: true + cache-dependency-path: go.sum + + - uses: actions/setup-node@v4 + with: + node-version: "22" + registry-url: "https://registry.npmjs.org" + + - uses: ./.github/actions/setup-bun + + - name: Configure Git + run: | + git config --global user.email "shuvcode@latitudes.dev" + git config --global user.name "shuvcode" + + - name: Publish + id: publish + run: | + ./script/publish.ts + env: + GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish Release (undraft) + if: success() && steps.publish.outputs.tagName + run: gh release edit ${{ steps.publish.outputs.tagName }} --draft=false + env: + GH_TOKEN: ${{ secrets.PAT_TOKEN }} + + - name: Post to Discord + if: success() && steps.publish.outputs.tagName + continue-on-error: true + run: ./script/discord-notify.ts + env: + DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + DISCORD_THREAD_ID: ${{ secrets.DISCORD_THREAD_ID }} + RELEASE_VERSION: ${{ steps.publish.outputs.tagName }} + RELEASE_CHANGELOG: ${{ steps.publish.outputs.changelog }} + - name: Deploy Desktop to Cloudflare + continue-on-error: true + run: | + bunx sst deploy --stage production --config sst.desktop.config.ts + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_DEFAULT_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + - name: Deploy Share to Cloudflare + continue-on-error: true + run: | + bunx sst deploy --stage production --config sst.share.config.ts + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_DEFAULT_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/stats.yml b/.github/workflows/stats.yml deleted file mode 100644 index 824733901d6..00000000000 --- a/.github/workflows/stats.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: stats - -on: - schedule: - - cron: "0 12 * * *" # Run daily at 12:00 UTC - workflow_dispatch: # Allow manual trigger - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -jobs: - stats: - if: github.repository == 'anomalyco/opencode' - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Run stats script - run: bun script/stats.ts - - - name: Commit stats - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add STATS.md - git diff --staged --quiet || git commit -m "ignore: update download stats $(date -I)" - git push - env: - POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }} diff --git a/.github/workflows/sync-zed-extension.yml b/.github/workflows/sync-zed-extension.yml deleted file mode 100644 index f14487cde97..00000000000 --- a/.github/workflows/sync-zed-extension.yml +++ /dev/null @@ -1,35 +0,0 @@ -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 index c39710bee8f..440f988a300 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,7 @@ on: push: branches: - dev + - integration pull_request: workflow_dispatch: jobs: diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml deleted file mode 100644 index 6e150957291..00000000000 --- a/.github/workflows/triage.yml +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index 011e23f5f6f..00000000000 --- a/.github/workflows/typecheck.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: typecheck - -on: - pull_request: - branches: [dev] - workflow_dispatch: - -jobs: - typecheck: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Bun - 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 deleted file mode 100644 index d2c60b08f01..00000000000 --- a/.github/workflows/update-nix-hashes.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Update Nix Hashes - -permissions: - contents: write - -on: - workflow_dispatch: - push: - paths: - - "bun.lock" - - "package.json" - - "packages/*/package.json" - pull_request: - paths: - - "bun.lock" - - "package.json" - - "packages/*/package.json" - -jobs: - update: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - runs-on: blacksmith-4vcpu-ubuntu-2404 - env: - SYSTEM: x86_64-linux - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - 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: DeterminateSystems/nix-installer-action@v20 - - - name: Configure git - run: | - git config --global user.email "action@github.com" - git config --global user.name "Github Action" - - - name: Update flake.lock - run: | - set -euo pipefail - echo "📦 Updating flake.lock..." - nix flake update - echo "✅ flake.lock updated successfully" - - - name: Update node_modules hash - run: | - set -euo pipefail - echo "🔄 Updating node_modules hash..." - nix/scripts/update-hashes.sh - echo "✅ node_modules hash updated successfully" - - - name: Commit hash changes - env: - TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} - run: | - set -euo pipefail - - echo "🔍 Checking for changes in tracked Nix files..." - - summarize() { - local status="$1" - { - echo "### Nix Hash Update" - 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=(flake.lock flake.nix nix/node-modules.nix nix/hashes.json) - STATUS="$(git status --short -- "${FILES[@]}" || true)" - if [ -z "$STATUS" ]; then - echo "✅ No changes detected. Hashes are already up to date." - summarize "no changes" - exit 0 - fi - - echo "📝 Changes detected:" - echo "$STATUS" - echo "🔗 Staging files..." - git add "${FILES[@]}" - echo "💾 Committing changes..." - git commit -m "Update Nix flake.lock and hashes" - echo "✅ Changes committed" - - BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}" - echo "🌳 Pulling latest from branch: $BRANCH" - git pull --rebase origin "$BRANCH" - echo "🚀 Pushing changes to branch: $BRANCH" - git push origin HEAD:"$BRANCH" - echo "✅ Changes pushed successfully" - - summarize "committed $(git rev-parse --short HEAD)" diff --git a/.github/workflows/upstream-sync.yml b/.github/workflows/upstream-sync.yml new file mode 100644 index 00000000000..6f3fb7f68b2 --- /dev/null +++ b/.github/workflows/upstream-sync.yml @@ -0,0 +1,755 @@ +name: Upstream Sync + +on: + repository_dispatch: + types: [upstream-release] + workflow_dispatch: + inputs: + tag: + description: "Tag to sync (leave empty for latest)" + type: string + required: false + +concurrency: + group: upstream-sync + cancel-in-progress: false + +permissions: + contents: write + issues: write + +jobs: + resolve-tag: + runs-on: blacksmith-2vcpu-ubuntu-2404 + outputs: + latest_tag: ${{ steps.resolve.outputs.latest_tag }} + latest_sha: ${{ steps.resolve.outputs.latest_sha }} + should_sync: ${{ steps.resolve.outputs.should_sync }} + steps: + - name: Resolve tag and SHA + id: resolve + env: + GITHUB_TOKEN: ${{ github.token }} + INPUT_TAG: ${{ github.event.client_payload.tag || inputs.tag }} + run: | + set -euo pipefail + + api() { + curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" "$1" + } + + # Use provided tag or fetch latest + if [ -n "${INPUT_TAG:-}" ]; then + LATEST_TAG="$INPUT_TAG" + else + RELEASE=$(api "https://api.github.com/repos/sst/opencode/releases/latest") + LATEST_TAG=$(echo "$RELEASE" | jq -r '.tag_name') + fi + + if [ -z "$LATEST_TAG" ] || [ "$LATEST_TAG" = "null" ]; then + echo "Unable to determine tag" >&2 + exit 1 + fi + + # Check if already synced (early exit to prevent duplicate work) + LAST_SYNCED=$(api "https://api.github.com/repos/${{ github.repository }}/contents/.github/last-synced-tag?ref=integration" | jq -r '.content' | base64 -d | tr -d '\n' || echo "") + if [ "$LATEST_TAG" = "$LAST_SYNCED" ]; then + echo "Tag $LATEST_TAG already synced, skipping" + echo "latest_tag=$LATEST_TAG" >> "$GITHUB_OUTPUT" + echo "latest_sha=" >> "$GITHUB_OUTPUT" + echo "should_sync=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Resolve tag to commit SHA + TAG_REF=$(api "https://api.github.com/repos/sst/opencode/git/ref/tags/$LATEST_TAG") + REF_TYPE=$(echo "$TAG_REF" | jq -r '.object.type') + REF_SHA=$(echo "$TAG_REF" | jq -r '.object.sha') + + if [ "$REF_TYPE" = "tag" ]; then + TAG_OBJECT=$(api "https://api.github.com/repos/sst/opencode/git/tags/$REF_SHA") + LATEST_SHA=$(echo "$TAG_OBJECT" | jq -r '.object.sha') + else + LATEST_SHA="$REF_SHA" + fi + + echo "Resolved tag: $LATEST_TAG -> $LATEST_SHA" + echo "latest_tag=$LATEST_TAG" >> "$GITHUB_OUTPUT" + echo "latest_sha=$LATEST_SHA" >> "$GITHUB_OUTPUT" + echo "should_sync=true" >> "$GITHUB_OUTPUT" + + merge-upstream: + needs: resolve-tag + if: needs.resolve-tag.outputs.should_sync == 'true' + runs-on: blacksmith-4vcpu-ubuntu-2404 + outputs: + merge_status: ${{ steps.merge.outputs.status }} + conflict_files: ${{ steps.merge.outputs.conflict_files }} + steps: + - name: Checkout integration branch + uses: actions/checkout@v4 + with: + ref: integration + fetch-depth: 0 + token: ${{ secrets.PAT_TOKEN }} + + - name: Setup Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Add upstream remote + run: | + git remote add upstream https://github.com/sst/opencode.git 2>/dev/null || true + + - name: Fetch upstream tag + run: | + git fetch upstream tag ${{ needs.resolve-tag.outputs.latest_tag }} --no-tags + + - name: Attempt merge + id: merge + run: | + # Attempt merge with no-commit to detect conflicts first + if git merge ${{ needs.resolve-tag.outputs.latest_tag }} --no-commit --no-ff 2>&1; then + echo "Merge successful, no conflicts" + # Check if there are changes to commit + if git diff --cached --quiet; then + echo "Already up to date, nothing to merge" + echo "status=up-to-date" >> $GITHUB_OUTPUT + else + git commit -m "sync: merge upstream ${{ needs.resolve-tag.outputs.latest_tag }} into integration" + echo "status=success" >> $GITHUB_OUTPUT + fi + else + # Check for conflicts + CONFLICTS=$(git diff --name-only --diff-filter=U) + if [ -n "$CONFLICTS" ]; then + echo "Conflicts detected in: $CONFLICTS" + echo "status=conflict" >> $GITHUB_OUTPUT + echo "conflict_files<> $GITHUB_OUTPUT + echo "$CONFLICTS" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Attempt auto-resolution for known patterns + UNRESOLVED="" + for file in $CONFLICTS; do + # Skip files in .gitignore (like .opencode/) - reset them instead + if git check-ignore -q "$file" 2>/dev/null; then + echo "Skipping ignored file: $file (resetting to HEAD)" + git checkout HEAD -- "$file" 2>/dev/null || git rm --cached -f "$file" 2>/dev/null || true + continue + fi + + case "$file" in + bun.lock) + echo "Auto-resolving bun.lock by accepting upstream..." + git checkout --theirs bun.lock 2>/dev/null || true + git add bun.lock + ;; + *.md) + echo "Auto-resolving $file (accepting upstream)..." + git checkout --theirs "$file" + git add "$file" + ;; + *) + UNRESOLVED="$UNRESOLVED $file" + ;; + esac + done + + # Check if all conflicts were resolved + REMAINING=$(git diff --name-only --diff-filter=U) + if [ -z "$REMAINING" ]; then + echo "All conflicts auto-resolved" + git commit -m "sync: merge upstream ${{ needs.resolve-tag.outputs.latest_tag }} into integration (auto-resolved conflicts)" + echo "status=auto-resolved" >> $GITHUB_OUTPUT + else + echo "Unresolved conflicts remain: $REMAINING" + git merge --abort + echo "status=needs-manual" >> $GITHUB_OUTPUT + fi + else + echo "Merge failed for unknown reason" + git merge --abort 2>/dev/null || true + echo "status=failed" >> $GITHUB_OUTPUT + fi + fi + + - name: Push integration branch + if: steps.merge.outputs.status == 'success' || steps.merge.outputs.status == 'auto-resolved' + run: | + git push origin integration + + - name: Update last synced tag marker + if: steps.merge.outputs.status == 'success' || steps.merge.outputs.status == 'auto-resolved' || steps.merge.outputs.status == 'up-to-date' + run: | + echo "${{ needs.resolve-tag.outputs.latest_tag }}" > .github/last-synced-tag + git add .github/last-synced-tag + git commit -m "sync: record last synced tag ${{ needs.resolve-tag.outputs.latest_tag }}" || true + git push origin integration || true + + validate: + needs: [resolve-tag, merge-upstream] + if: needs.merge-upstream.outputs.merge_status == 'success' || needs.merge-upstream.outputs.merge_status == 'auto-resolved' || needs.merge-upstream.outputs.merge_status == 'up-to-date' + runs-on: blacksmith-4vcpu-ubuntu-2404 + outputs: + validation_status: ${{ steps.validate.outputs.status }} + validation_error: ${{ steps.validate.outputs.error }} + steps: + - name: Checkout integration branch + uses: actions/checkout@v4 + with: + ref: integration + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.3 + + - name: Install dependencies + run: bun install + + - name: Run validation + id: validate + run: | + set +e + + echo "Running typecheck..." + bun turbo typecheck + if [ $? -ne 0 ]; then + echo "status=failed" >> $GITHUB_OUTPUT + echo "error=typecheck failed" >> $GITHUB_OUTPUT + exit 1 + fi + + echo "Running tests..." + bun turbo test + if [ $? -ne 0 ]; then + echo "status=failed" >> $GITHUB_OUTPUT + echo "error=tests failed" >> $GITHUB_OUTPUT + exit 1 + fi + + echo "Running build..." + bun turbo build + if [ $? -ne 0 ]; then + echo "status=failed" >> $GITHUB_OUTPUT + echo "error=build failed" >> $GITHUB_OUTPUT + exit 1 + fi + + echo "status=success" >> $GITHUB_OUTPUT + + create-issue: + needs: [resolve-tag, merge-upstream, validate] + if: | + always() && + (needs.merge-upstream.outputs.merge_status == 'needs-manual' || + needs.merge-upstream.outputs.merge_status == 'failed' || + needs.validate.outputs.validation_status == 'failed') + runs-on: blacksmith-4vcpu-ubuntu-2404 + outputs: + issue_number: ${{ steps.create-conflict-issue.outputs.issue_number || steps.create-validation-issue.outputs.issue_number }} + steps: + - name: Checkout integration branch + uses: actions/checkout@v4 + with: + ref: integration + + - name: Create conflict issue + id: create-conflict-issue + if: needs.merge-upstream.outputs.merge_status == 'needs-manual' + uses: actions/github-script@v7 + with: + script: | + const conflictFiles = `${{ needs.merge-upstream.outputs.conflict_files }}`; + const latestTag = `${{ needs.resolve-tag.outputs.latest_tag }}`; + const latestSha = `${{ needs.resolve-tag.outputs.latest_sha }}`; + const issueTitle = `[Upstream Sync] Merge conflict with ${latestTag}`; + + // Check if an issue with this title already exists + const existingIssues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + labels: 'upstream-sync' + }); + + const duplicate = existingIssues.data.find(issue => issue.title === issueTitle); + if (duplicate) { + console.log(`Issue already exists: #${duplicate.number}`); + core.setOutput('issue_number', duplicate.number); + core.setOutput('is_duplicate', 'true'); + return; + } + + const body = `## Upstream Sync Conflict Report + + **Trigger**: Upstream sync at ${new Date().toISOString()} + **Upstream Tag**: ${latestTag} + **Upstream SHA**: ${latestSha} + + ### Conflicting Files + + \`\`\` + ${conflictFiles} + \`\`\` + + ### Recommended Actions + + 1. Checkout integration branch locally + 2. Run: \`git fetch upstream && git merge ${latestTag}\` + 3. Resolve conflicts manually + 4. Run validation: \`bun install && bun turbo typecheck && bun turbo test\` + 5. Push resolved integration branch + 6. Close this issue + + ### Manual Sync Commands + + \`\`\`bash + git remote add upstream https://github.com/sst/opencode.git 2>/dev/null || true + git fetch upstream --tags + git checkout integration + git merge ${latestTag} + # Resolve conflicts... + bun install + bun turbo typecheck + bun turbo test + git push origin integration + \`\`\` + `; + + const issue = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: issueTitle, + body: body, + labels: ['upstream-sync', 'needs-manual-review'] + }); + + core.setOutput('issue_number', issue.data.number); + core.setOutput('is_duplicate', 'false'); + + - name: Create validation failure issue + id: create-validation-issue + if: needs.validate.outputs.validation_status == 'failed' + uses: actions/github-script@v7 + with: + script: | + const latestTag = `${{ needs.resolve-tag.outputs.latest_tag }}`; + const error = `${{ needs.validate.outputs.validation_error }}`; + const issueTitle = `[Upstream Sync] Validation failed after merging ${latestTag}`; + + // Check if an issue with this title already exists + const existingIssues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + labels: 'upstream-sync' + }); + + const duplicate = existingIssues.data.find(issue => issue.title === issueTitle); + if (duplicate) { + console.log(`Issue already exists: #${duplicate.number}`); + core.setOutput('issue_number', duplicate.number); + core.setOutput('is_duplicate', 'true'); + return; + } + + const body = `## Upstream Sync Validation Failure + + **Trigger**: Upstream sync at ${new Date().toISOString()} + **Upstream Tag**: ${latestTag} + **Error**: ${error} + + ### What happened + + The upstream sync merged successfully, but post-merge validation failed. + + ### Recommended Actions + + 1. Check the [workflow run](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}) for detailed logs + 2. Checkout integration branch locally + 3. Run the failing validation step locally to debug + 4. Fix any issues and push to integration + + ### Validation Commands + + \`\`\`bash + git fetch origin + git checkout integration + bun install + bun turbo typecheck + bun turbo test + bun turbo build + \`\`\` + `; + + const issue = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: issueTitle, + body: body, + labels: ['upstream-sync', 'needs-manual-review'] + }); + + core.setOutput('issue_number', issue.data.number); + core.setOutput('is_duplicate', 'false'); + + close-issues-on-success: + needs: [resolve-tag, merge-upstream, validate] + if: | + always() && + needs.validate.outputs.validation_status == 'success' && + (needs.merge-upstream.outputs.merge_status == 'success' || needs.merge-upstream.outputs.merge_status == 'auto-resolved') + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - name: Close related upstream-sync issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.PAT_TOKEN }} + script: | + const latestTag = `${{ needs.resolve-tag.outputs.latest_tag }}`; + + // Find all open upstream-sync issues + const issues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + labels: 'upstream-sync' + }); + + for (const issue of issues.data) { + // Close issues related to this tag or older + if (issue.title.includes('[Upstream Sync]')) { + console.log(`Closing issue #${issue.number}: ${issue.title}`); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `✅ Automatically closed - upstream sync to ${latestTag} completed successfully.\n\nValidation passed: typecheck, tests, and build all succeeded.` + }); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: 'completed' + }); + } + } + + trigger-opencode: + needs: [resolve-tag, merge-upstream, create-issue] + if: | + always() && + needs.create-issue.outputs.issue_number != '' + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - name: Checkout integration branch + uses: actions/checkout@v4 + with: + ref: integration + + - name: Read fork features + id: fork-features + run: | + if [ -f "script/sync/fork-features.json" ]; then + # Extract features as a formatted list for the prompt + FEATURES=$(cat script/sync/fork-features.json | jq -r '.features[] | "- PR #\(.pr): \(.title) (@\(.author))\n Files: \(.files | join(", "))\n Description: \(.description)"') + echo "features<> $GITHUB_OUTPUT + echo "$FEATURES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Extract just the file paths for conflict matching + FILES=$(cat script/sync/fork-features.json | jq -r '[.features[].files[]] | unique | .[]') + echo "files<> $GITHUB_OUTPUT + echo "$FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + else + echo "features=" >> $GITHUB_OUTPUT + echo "files=" >> $GITHUB_OUTPUT + fi + + - name: Trigger opencode to resolve conflicts + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.PAT_TOKEN }} + script: | + const issueNumber = parseInt(`${{ needs.create-issue.outputs.issue_number }}`); + const latestTag = `${{ needs.resolve-tag.outputs.latest_tag }}`; + const conflictFiles = `${{ needs.merge-upstream.outputs.conflict_files }}`; + const mergeStatus = `${{ needs.merge-upstream.outputs.merge_status }}`; + const forkFeatures = `${{ steps.fork-features.outputs.features }}`; + const forkFeatureFiles = `${{ steps.fork-features.outputs.files }}`; + + // Build the opencode prompt based on the issue type + let prompt; + + if (mergeStatus === 'needs-manual') { + prompt = `/opencode + + ## Task: Resolve Upstream Merge Conflicts + + Sync the shuvcode fork from upstream sst/opencode tag **${latestTag}**, resolve all merge conflicts, and complete the integration. + + ### Repository Context + - **Upstream**: \`sst/opencode\` (original project) + - **Fork**: \`Latitudes-Dev/shuvcode\` (customized downstream fork) + - **Integration branch**: \`integration\` (where we merge upstream changes) + + ### Conflicting Files + \`\`\` + ${conflictFiles} + \`\`\` + + ### CRITICAL: Fork Feature Files (MUST PRESERVE) + + This fork contains features from upstream PRs that have NOT yet been merged upstream. + These features MUST be preserved during the merge. The fork-features.json file at + \`script/sync/fork-features.json\` contains the authoritative list. + + **Merged PRs in this fork:** + ${forkFeatures} + + **Fork feature files that require special handling:** + \`\`\` + ${forkFeatureFiles} + \`\`\` + + **IMPORTANT**: When any of these files have conflicts: + 1. Do NOT simply accept upstream changes - this will DELETE our features + 2. Carefully merge to preserve BOTH upstream improvements AND our fork features + 3. Read the file content before and after to verify features are preserved + 4. Test that the feature still works after merging + + ### Conflict Resolution Strategy + + Follow these resolution patterns for each file type: + + | File Pattern | Resolution | + |--------------|------------| + | Fork feature files (see above) | **MERGE CAREFULLY** - preserve our features while integrating upstream changes | + | \`STATS.md\`, \`nix/hashes.json\` | Accept upstream (\`git checkout --theirs\`) | + | \`bun.lock\` | Delete and regenerate with \`bun install\` | + | \`packages/opencode/script/publish.ts\` | Keep ours (fork-specific publishing) | + | \`packages/opencode/script/build.ts\` | Keep ours (shuvcode naming) | + | \`packages/opencode/bin/opencode\` | Keep ours (shuvcode binary lookup) | + | \`packages/script/src/index.ts\` | Keep ours (version logic) | + | \`.github/*\` workflow configs | Keep ours (fork-specific workflows) | + | \`README.md\` | Keep ours (fork-specific documentation with PR table) | + + ### Step-by-Step Instructions + + 1. **Review fork-features.json first**: + \`\`\`bash + cat script/sync/fork-features.json + \`\`\` + This file lists all PRs and their files that MUST be preserved. + + 2. **Setup upstream remote and fetch**: + \`\`\`bash + git remote add upstream https://github.com/sst/opencode.git 2>/dev/null || true + git fetch upstream --tags + \`\`\` + + 3. **Start the merge**: + \`\`\`bash + git merge ${latestTag} --no-commit --no-ff + \`\`\` + + 4. **List conflicts and identify fork feature files**: + \`\`\`bash + git diff --name-only --diff-filter=U + \`\`\` + Cross-reference with fork-features.json to identify critical files. + + 5. **For fork feature file conflicts**: Read both versions, understand the changes, and manually merge to preserve our features while integrating upstream improvements. + + 6. **For each resolved file**: + \`\`\`bash + git add + \`\`\` + + 7. **Verify no conflicts remain**: + \`\`\`bash + git diff --name-only --diff-filter=U # Should be empty + \`\`\` + + 8. **Regenerate lockfile** (if bun.lock was conflicted): + \`\`\`bash + rm -f bun.lock + bun install + git add bun.lock + \`\`\` + + 9. **Commit the merge**: + \`\`\`bash + git commit -m "sync: merge upstream ${latestTag} into integration + + Resolved conflicts: + - + + Preserved fork features: + - " + \`\`\` + + 10. **Update sync marker**: + \`\`\`bash + echo "${latestTag}" > .github/last-synced-tag + git add .github/last-synced-tag + git commit -m "sync: record last synced tag ${latestTag}" + \`\`\` + + 11. **Run validation**: + \`\`\`bash + bun install + bun turbo typecheck + bun turbo test + \`\`\` + + 12. **Push branch to origin**: + \`\`\`bash + git push origin HEAD + \`\`\` + + 13. **Create or find existing PR**: + \`\`\`bash + # Check if PR already exists for this branch + EXISTING_PR=$(gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number' --repo Latitudes-Dev/shuvcode 2>/dev/null || echo "") + if [ -n "$EXISTING_PR" ]; then + echo "PR #$EXISTING_PR already exists" + PR_NUMBER=$EXISTING_PR + else + # Create PR targeting integration branch + PR_URL=$(gh pr create --title "sync: merge upstream ${latestTag}" --body "Resolves conflicts from upstream ${latestTag} merge. Closes #${issueNumber}" --base integration --repo Latitudes-Dev/shuvcode) + PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') + echo "Created PR #$PR_NUMBER" + fi + \`\`\` + + 14. **Wait for CI checks to pass, then merge the PR**: + \`\`\`bash + # Wait for checks and merge (auto-merge when checks pass) + gh pr merge "$PR_NUMBER" --squash --auto --delete-branch --repo Latitudes-Dev/shuvcode + \`\`\` + + 15. **Close this issue** after PR is merged: + \`\`\`bash + gh issue close ${issueNumber} --comment "Resolved - merged upstream ${latestTag} via PR #$PR_NUMBER" --repo Latitudes-Dev/shuvcode + \`\`\` + + ### Important Notes + - **Never force-push** to integration branch + - **Always preserve fork-specific changes** in publish.ts, build.ts, bin/opencode + - **CRITICAL**: Always preserve fork feature files listed in fork-features.json + - If validation fails, fix the issues before pushing + - The PR will be auto-merged once CI checks pass, triggering the snapshot workflow + `; + } else { + // Validation failure case + prompt = `/opencode + + ## Task: Fix Validation Failures After Upstream Merge + + The upstream merge of **${latestTag}** succeeded, but post-merge validation failed. + + ### Fork Features Context + + This fork contains features from upstream PRs that have NOT yet been merged upstream. + Review \`script/sync/fork-features.json\` to understand what features must be preserved. + Validation failures may be related to conflicts between upstream changes and our fork features. + + **Merged PRs in this fork:** + ${forkFeatures} + + ### Instructions + + 1. **Review fork-features.json**: + \`\`\`bash + cat script/sync/fork-features.json + \`\`\` + + 2. **Pull the latest integration branch**: + \`\`\`bash + git fetch origin + git checkout integration + git pull origin integration + \`\`\` + + 3. **Install dependencies**: + \`\`\`bash + bun install + \`\`\` + + 4. **Run validation and identify failures**: + \`\`\`bash + bun turbo typecheck + bun turbo test + bun turbo build + \`\`\` + + 5. **Fix any type errors, test failures, or build issues** + - If failures are in fork feature files, ensure you preserve the feature functionality + - Cross-reference with fork-features.json to understand what each file should contain + + 6. **Commit fixes**: + \`\`\`bash + git add . + git commit -m "fix: resolve validation issues after merging ${latestTag}" + \`\`\` + + 7. **Re-run validation to confirm fixes**: + \`\`\`bash + bun turbo typecheck && bun turbo test && bun turbo build + \`\`\` + + 8. **Push branch to origin**: + \`\`\`bash + git push origin HEAD + \`\`\` + + 9. **Create or find existing PR**: + \`\`\`bash + # Check if PR already exists for this branch + EXISTING_PR=$(gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number' --repo Latitudes-Dev/shuvcode 2>/dev/null || echo "") + if [ -n "$EXISTING_PR" ]; then + echo "PR #$EXISTING_PR already exists" + PR_NUMBER=$EXISTING_PR + else + # Create PR targeting integration branch + PR_URL=$(gh pr create --title "fix: resolve validation issues after ${latestTag}" --body "Fixes validation failures from upstream ${latestTag} merge. Closes #${issueNumber}" --base integration --repo Latitudes-Dev/shuvcode) + PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') + echo "Created PR #$PR_NUMBER" + fi + \`\`\` + + 10. **Wait for CI checks to pass, then merge the PR**: + \`\`\`bash + # Wait for checks and merge (auto-merge when checks pass) + gh pr merge "$PR_NUMBER" --squash --auto --delete-branch --repo Latitudes-Dev/shuvcode + \`\`\` + + 11. **Close this issue** after PR is merged: + \`\`\`bash + gh issue close ${issueNumber} --comment "Fixed validation issues after merging ${latestTag} via PR #$PR_NUMBER" --repo Latitudes-Dev/shuvcode + \`\`\` + `; + } + + // Post the comment to trigger opencode + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + body: prompt + }); + + console.log(`Posted opencode trigger comment on issue #${issueNumber}`); diff --git a/.gitignore b/.gitignore index fc175568df6..76ec47537d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store node_modules +.opencode .worktrees .sst .env @@ -20,7 +21,9 @@ opencode.json a.out target .scripts +docker/workspace # Local dev files opencode-dev logs/ +.loop* diff --git a/.opencode/agent/docs.md b/.opencode/agent/docs.md deleted file mode 100644 index 21cfc6a16e0..00000000000 --- a/.opencode/agent/docs.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -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 -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 separated by a divider of 3 dashes - -The section titles are short with only the first letter of the word capitalized - -The section titles are in the imperative mood - -The section titles should not repeat the term used in the page title, for -example, if the page title is "Models", avoid using a section title like "Add -new models". This might be unavoidable in some cases, but try to avoid it. - -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/triage.md b/.opencode/agent/triage.md deleted file mode 100644 index 539be154917..00000000000 --- a/.opencode/agent/triage.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -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". Zen is our gateway for coding models. **Do not** add for other gateways or inference providers. - -If the issue doesn't have "zen" 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/commit.md b/.opencode/command/commit.md deleted file mode 100644 index 8e9346ebc88..00000000000 --- a/.opencode/command/commit.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -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 deleted file mode 100644 index 75b59616743..00000000000 --- a/.opencode/command/issues.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -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 deleted file mode 100644 index 02c9fc0844a..00000000000 --- a/.opencode/command/rmslop.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -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 deleted file mode 100644 index 0abf23c4fd0..00000000000 --- a/.opencode/command/spellcheck.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -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 deleted file mode 100644 index f2b13a934c4..00000000000 --- a/.opencode/env.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.txt" { - const content: string - export default content -} diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc deleted file mode 100644 index 5d2dec625c6..00000000000 --- a/.opencode/opencode.jsonc +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$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/themes/mytheme.json b/.opencode/themes/mytheme.json deleted file mode 100644 index e444de807c6..00000000000 --- a/.opencode/themes/mytheme.json +++ /dev/null @@ -1,223 +0,0 @@ -{ - "$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-triage.ts b/.opencode/tool/github-triage.ts deleted file mode 100644 index 1e216f1c8da..00000000000 --- a/.opencode/tool/github-triage.ts +++ /dev/null @@ -1,90 +0,0 @@ -/// -// 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 deleted file mode 100644 index 4c46a72c162..00000000000 --- a/.opencode/tool/github-triage.txt +++ /dev/null @@ -1,88 +0,0 @@ -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/AGENTS.md b/AGENTS.md index 87d59d4c923..c799e9b9228 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,27 @@ +## IMPORTANT + +- This is a FORK of sst/opencode - the fork repo is Latitudes-Dev/shuvcode +- NEVER create PRs against upstream (sst/opencode) +- ALWAYS use `--repo Latitudes-Dev/shuvcode` when creating PRs with `gh` +- All PRs should target the fork repository, not upstream + +## Debugging + - To test opencode in the `packages/opencode` directory you can 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` + +## Testing +- Avoid testing logic directly inside Solid.js `.tsx` files if they import JSX runtimes, as `bun test` may fail with `jsxDEV` errors. +- Separate pure logic into `.ts` files (e.g., `theme-utils.ts`) and test those instead. + +## Upstream Merge Operations + + +When merging upstream tags (e.g., v1.1.1): +1. Use `git merge --no-commit` to start merge without auto-commit +2. List conflicts: `git diff --name-only --diff-filter=U` +3. Cannot commit plan updates mid-merge - all conflict resolution must complete first +4. For files deleted in fork but modified upstream (delete/modify conflicts), decide per-file: + - `.opencode/*` files are upstream-specific, delete them: `git rm ` diff --git a/CONTEXT/PLAN-264-266-pwa-menu-audio-bundling-2026-01-05.md b/CONTEXT/PLAN-264-266-pwa-menu-audio-bundling-2026-01-05.md new file mode 100644 index 00000000000..c36f086bd88 --- /dev/null +++ b/CONTEXT/PLAN-264-266-pwa-menu-audio-bundling-2026-01-05.md @@ -0,0 +1,462 @@ +## Plan Overview +Address two open bugs: PWA safe-area/scroll regressions (issue #264) and plugin audio asset bundling (issue #266). This plan captures current code context, decision points from issues, external references, and a sequenced task list with validation steps. + +**Revision Note (v1):** This plan has been revised based on codebase review to address CSS selector mismatches, missing implementation details, and PWA detection gaps. + +**Revision Note (v2 - 2026-01-06):** Plan reviewed against codebase. Added explicit directory creation, single-file plugin handling, PullToRefresh refactor details, and additional audio formats. + +## Source Issues +| Issue | Title | Link | Acceptance Criteria (abridged) | +| --- | --- | --- | --- | +| #264 | fix(pwa): Menu button hidden behind Dynamic Island and viewport scrolling not locked on iOS PWA | https://github.com/Latitudes-Dev/shuvcode/issues/264 | Menu buttons visible below Dynamic Island; session viewport locked; consistent PWA behavior; no desktop regressions; works on Dynamic Island + notch devices; Android pull-to-refresh regression noted in comment. | +| #266 | Plugin bundling doesn't copy audio files (.wav) breaking opencode-notifier sounds | https://github.com/Latitudes-Dev/shuvcode/issues/266 | Bundling copies audio assets; sounds work; assets discoverable relative to bundled plugin dir; likely include other audio formats. | + +## Context Capture and Decisions +### Issue #266 (Plugin audio assets) +- Bundled plugins are built with `Bun.build()` in `packages/opencode/src/bun/index.ts`. +- Non-JS assets are copied via `copyPluginAssets()` but only for a limited extension list (no audio). +- `copyPluginAssets()` currently flattens paths via `path.basename(entry)` which drops subdirectory structure (`bun/index.ts:235`). +- `@mohak34/opencode-notifier` resolves sounds via `__dirname/../sounds/*.wav`, so flattening + missing `.wav` results in missing files after bundling. +- Bundled assets are copied to both the package bundle directory and `Global.Path.cache` for runtime resolution. +- **GAP IDENTIFIED:** Local plugin bundling in `packages/opencode/src/plugin/index.ts:25-79` (`bundleLocalPlugin()`) does NOT call any asset copy logic after bundling. +- **GAP IDENTIFIED:** Local plugin bundling only has an entry file path; asset copying needs a reliable plugin root (for `sounds/` and similar directories). + +Decisions: +- Expand `assetExtensions` to include audio formats (`.wav`, `.mp3`, `.ogg`, `.flac`, `.m4a`) AND video/font formats for future-proofing (`.mp4`, `.webm`, `.woff`, `.woff2`, `.ttf`). +- Preserve plugin directory structure when copying assets (use the relative entry path, not `basename`). +- Ensure the copy logic creates parent directories before writing nested files using `Bun.$\`mkdir -p\``. +- **CONFIRMED:** Local `file://` plugins MUST also get asset copying. Extract `copyPluginAssets()` to a shared utility at `packages/opencode/src/util/asset-copy.ts`. +- Resolve a local plugin root before copying assets (walk up from the entry file to the nearest `package.json`, fallback to `path.dirname(filePath)`). +- Copy local plugin assets into both the bundled-local output directory and `Global.Path.cache` to preserve `__dirname/..` resolution parity with npm bundles. +- Guard against unsafe paths or symlinks in asset copying (skip entries that escape `pluginDir` or are symlinks, if detectable). +- Collision risk: assets are copied into shared dirs (`bundled`, `bundled-local`, `Global.Path.cache`). Keep this for compatibility, but log when overwriting an existing asset to surface conflicts. + +### Issue #264 (PWA safe area + viewport locking) +- Home menu button is absolutely positioned at `top-0 left-0 p-2` without safe-area offset in `packages/app/src/pages/home.tsx:35-41`. +- **CRITICAL GAP:** Session header (`packages/app/src/components/session/session-header.tsx:52`) does NOT have `data-tauri-drag-region` attribute, but existing CSS rule at `index.css:109-112` targets `header[data-tauri-drag-region]`. The CSS selector does not match. +- PWA-related safe area variables are defined in `packages/app/src/index.css:8-11`. +- `isPWA()` already exists in `packages/app/src/context/platform.tsx:5-11` and can be reused. +- Mobile pages use `PullToRefresh` wrapper in `packages/app/src/pages/layout.tsx:1177-1179` which can trigger pull-to-refresh. The issue comment notes Android refresh on downward swipe. +- **GAP IDENTIFIED:** `PullToRefresh` component has no mechanism to detect PWA standalone mode. +- Session view has scroll container at `packages/app/src/pages/session.tsx:906` with class `overflow-y-auto no-scrollbar` but no `overscroll-behavior` constraint. + +Decisions: +- Use the existing `isPWA()` in `packages/app/src/context/platform.tsx` instead of adding a new utility. +- Keep PWA styling based on `@media (display-mode: standalone)` (avoid `data-pwa` attributes that would add another detection path). +- Add `.home-menu-button` and `.session-scroll-container` classes and extend existing PWA media-query rules in `index.css`. +- Add `data-tauri-drag-region` to the session header so the existing PWA safe-area rule applies. +- Keep the mobile scroll container from `PullToRefresh` but disable refresh behavior in PWA mode (add a prop or internal PWA check instead of removing the wrapper). + +## External References (for asset copy patterns) +- https://github.com/mohak34/opencode-notifier (plugin using `sounds/*.wav`) +- https://github.com/jadujoel/bun-copy-plugin (Bun build copy plugin reference) +- https://github.com/noriyotcp/esbuild-plugin-just-copy (asset copy with preserved paths) + +## Relevant Internal Files +| File | Purpose | Key Lines | +| --- | --- | --- | +| `packages/opencode/src/bun/index.ts` | npm plugin bundling | `copyPluginAssets()` at L224-253, `assetExtensions` at L226 | +| `packages/opencode/src/plugin/index.ts` | local plugin bundling | `bundleLocalPlugin()` at L25-79 (missing asset copy) | +| `packages/app/src/pages/home.tsx` | home page with menu button | Menu button at L35-41 (`top-0 left-0`) | +| `packages/app/src/components/session/session-header.tsx` | session header | Header at L52 (missing `data-tauri-drag-region`) | +| `packages/app/src/pages/session.tsx` | session view | Scroll container at L906 | +| `packages/app/src/pages/layout.tsx` | layout with PullToRefresh | PullToRefresh wrapper at L1177-1179 | +| `packages/app/src/components/pull-to-refresh.tsx` | pull-to-refresh component | Scroll container + refresh logic | +| `packages/app/src/context/platform.tsx` | platform utils | `isPWA()` at L5-11 | +| `packages/app/src/index.css` | PWA CSS rules | Safe-area vars L8-11, PWA rules L90-121 | +| `packages/app/index.html` | HTML entry | Body classes at L27 | + +## Technical Specifications + +### Plugin Asset Bundling (Issue #266) + +#### Asset Extensions (Expanded) +```ts +const ASSET_EXTENSIONS = [ + // Existing + ".html", ".css", ".json", ".txt", ".svg", ".png", ".jpg", ".gif", + // Audio (new) + ".wav", ".mp3", ".ogg", ".flac", ".m4a", ".aac", ".webm", + // Video (new - future-proofing) + ".mp4", ".webm", ".mov", + // Fonts (new - future-proofing) + ".woff", ".woff2", ".ttf", ".otf" +] +``` + +**Note:** Use `ASSET_EXTENSIONS` (uppercase) for the shared constant to distinguish from local variables. + +#### Directory Structure Preservation +**Current (broken):** +```ts +// packages/opencode/src/bun/index.ts:235 +const destPath = path.join(destDir, path.basename(entry)) // Drops directory +await Bun.write(destPath, content) // No mkdir for nested paths +``` + +**Fixed:** +```ts +const destPath = path.join(destDir, entry) // Preserve relative path +await Bun.$`mkdir -p ${path.dirname(destPath)}` // Create parent dirs +await Bun.write(destPath, content) +``` + +#### Shared Asset Copy Utility +Create `packages/opencode/src/util/asset-copy.ts`: +```ts +import path from "path" +import fs from "fs" +import { Log } from "./log" + +const log = Log.create({ service: "asset-copy" }) + +export const ASSET_EXTENSIONS = [ + ".html", ".css", ".json", ".txt", ".svg", ".png", ".jpg", ".gif", + ".wav", ".mp3", ".ogg", ".flac", ".m4a", ".aac", + ".mp4", ".webm", ".mov", + ".woff", ".woff2", ".ttf", ".otf" +] + +/** + * Copy non-JS assets from a plugin directory to target directory. + * Preserves directory structure (e.g., sounds/alerts/beep.wav). + * + * @param pluginDir - Root directory to scan for assets (must be resolved) + * @param targetDir - Destination directory + */ +export async function copyPluginAssets(pluginDir: string, targetDir: string) { + const entries = await Array.fromAsync( + new Bun.Glob("**/*").scan({ cwd: pluginDir, dot: false }) + ) + + for (const entry of entries) { + const ext = path.extname(entry).toLowerCase() + if (!ASSET_EXTENSIONS.includes(ext)) continue + + const srcPath = path.join(pluginDir, entry) + const destPath = path.join(targetDir, entry) // Preserve structure + + // Security: Skip entries that escape pluginDir via symlinks or path traversal + const realSrcPath = await fs.promises.realpath(srcPath).catch(() => null) + if (!realSrcPath || !realSrcPath.startsWith(await fs.promises.realpath(pluginDir))) { + log.warn("skipping asset outside plugin directory", { src: entry }) + continue + } + + try { + // CRITICAL: Create parent directories before writing nested files + const destDir = path.dirname(destPath) + await Bun.$`mkdir -p ${destDir}`.quiet() + + // Log if overwriting existing file + const exists = await Bun.file(destPath).exists() + if (exists) { + log.info("overwriting existing plugin asset", { dest: destPath }) + } + + const content = await Bun.file(srcPath).arrayBuffer() + await Bun.write(destPath, content) + log.info("copied plugin asset", { src: entry, dest: destPath }) + } catch (e) { + log.error("failed to copy plugin asset", { + src: srcPath, + dest: destPath, + error: (e as Error).message, + }) + } + } +} + +/** + * Resolve the root directory of a local plugin. + * Walks up from the entry file to find nearest package.json. + * Falls back to the entry file's directory for single-file plugins. + * + * @param entryFilePath - Absolute path to the plugin entry file + * @returns Resolved plugin root directory + */ +export async function resolvePluginRoot(entryFilePath: string): Promise { + let dir = path.dirname(entryFilePath) + const root = path.parse(dir).root + + while (dir !== root) { + const pkgPath = path.join(dir, "package.json") + if (await Bun.file(pkgPath).exists()) { + return dir + } + dir = path.dirname(dir) + } + + // Fallback for single-file plugins without package.json + return path.dirname(entryFilePath) +} +``` + +**Implementation Notes:** +- `pluginDir` should be resolved via `resolvePluginRoot()` for local plugins +- Security: Uses `fs.promises.realpath()` to detect symlink escapes +- Collision detection: Logs when overwriting existing assets +- Directory creation: Uses `mkdir -p` BEFORE `Bun.write()` for nested paths +- Single-file plugins: Falls back to entry file's directory when no package.json exists + +### PWA Safe Area + Viewport Locking (Issue #264) + +#### PWA Detection Utility (existing) +Use the existing helper in `packages/app/src/context/platform.tsx`: +```ts +export function isPWA(): boolean { + if (typeof window === "undefined") return false + return ( + window.matchMedia("(display-mode: standalone)").matches || + // @ts-ignore - iOS Safari specific + window.navigator.standalone === true + ) +} +``` + +#### Home Menu Button Fix +**File:** `packages/app/src/pages/home.tsx:35-41` + +**Current:** +```tsx +
+``` + +**Fixed (CSS-based for consistency):** +```tsx +
+``` + +#### Session Header Fix +**File:** `packages/app/src/components/session/session-header.tsx:52` + +**Current:** +```tsx +
+``` + +**Fixed (match existing CSS selector):** +```tsx +
+``` + +#### CSS Rules (PWA-specific) +**File:** `packages/app/src/index.css` - Extend the existing `@media (display-mode: standalone)` block: + +```css +@media (display-mode: standalone) { + /* Existing header[data-tauri-drag-region] rule remains; ensure SessionHeader has the attribute */ + .home-menu-button { + top: var(--safe-area-inset-top); + } + + .session-scroll-container { + overscroll-behavior: contain; + } +} +``` + +#### Session Scroll Container Fix +**File:** `packages/app/src/pages/session.tsx:906` + +**Current:** +```tsx +class="relative min-w-0 w-full h-full overflow-y-auto no-scrollbar" +``` + +**Fixed:** +```tsx +class="relative min-w-0 w-full h-full overflow-y-auto no-scrollbar session-scroll-container" +``` + +#### PullToRefresh Guard +**File:** `packages/app/src/pages/layout.tsx:1177-1179` + +**Current:** +```tsx +
+ {props.children} +
+``` + +**Fixed (keep scroll container, disable refresh):** +```tsx +import { isPWA } from "@/context/platform" + +// In component: +const pwaMode = isPWA() + +// In render: +
+ {props.children} +
+``` + +**PullToRefresh component change (`packages/app/src/components/pull-to-refresh.tsx`):** +```tsx +export function PullToRefresh(props: ParentProps<{ enabled?: boolean }>) { + // ... existing signals ... + + // Reactive enabled check + const enabled = () => props.enabled !== false + + const handleTouchStart = (e: TouchEvent) => { + if (!enabled()) return // Early return when disabled + if (isRefreshing()) return + if (!canPull()) return + // ... rest of handler + } + + const handleTouchMove = (e: TouchEvent) => { + if (!enabled()) return // Early return when disabled + if (!isPulling() || isRefreshing()) return + // ... rest of handler + } + + const handleTouchEnd = async () => { + if (!enabled()) return // Early return when disabled + if (!isPulling()) return + // ... rest of handler + } + + // Note: Touch event listeners remain attached for scroll containment + // The enabled() guard prevents refresh behavior without removing listeners +} +``` + +**Why keep listeners attached:** The scroll container behavior (`overflow-y-auto`, `contain-strict`) should remain even when refresh is disabled. Only the pull-to-refresh gesture handling is guarded. + +### API/Config/Integration Points +- API endpoints: None added/changed. +- Config: `opencode.json` plugin list remains unchanged. +- Integration points: + - `copyPluginAssets()` moved to `packages/opencode/src/util/asset-copy.ts` (shared utility). + - Called from `packages/opencode/src/bun/index.ts` for npm plugins. + - Called from `packages/opencode/src/plugin/index.ts` for local plugins (after resolving plugin root). + - Reuse `isPWA()` from `packages/app/src/context/platform.tsx` in layout. + - `PullToRefresh` accepts an `enabled` prop to keep scroll container while disabling refresh. + - PWA CSS in `packages/app/src/index.css`. + +## Option Comparison (Asset Copy Strategy) +| Option | Summary | Pros | Cons | Decision | +| --- | --- | --- | --- | --- | +| Extend existing `copyPluginAssets()` | Update extensions + preserve directory structure | Minimal change, consistent with current bundling | Still manual copy logic | **SELECTED** | +| Introduce external copy helper/plugin | Use a bundler copy plugin | Potentially reusable | Adds dependency/config | Rejected | + +## Implementation Order and Milestones + +### Milestone 1: Fix plugin audio asset bundling (#266) +- [ ] Create shared utility `packages/opencode/src/util/asset-copy.ts`: + - Export `ASSET_EXTENSIONS` constant with audio, video, font formats + - Export `copyPluginAssets(pluginDir, targetDir)` with directory preservation + - Export `resolvePluginRoot(entryFilePath)` to find nearest package.json or fallback + - Include symlink/path traversal security checks via `fs.promises.realpath()` + - Log overwrites when copying to shared target directories +- [ ] Update `packages/opencode/src/bun/index.ts`: + - Import `{ copyPluginAssets, ASSET_EXTENSIONS }` from shared utility + - Remove inline `copyPluginAssets` function and `assetExtensions` array + - Preserve existing call sites: `copyPluginAssets(mod, bundledDir)` and `copyPluginAssets(mod, Global.Path.cache)` +- [ ] Update `packages/opencode/src/plugin/index.ts` `bundleLocalPlugin()`: + - Import `{ copyPluginAssets, resolvePluginRoot }` from shared utility + - After successful `Bun.build()`, resolve plugin root: `const pluginRoot = await resolvePluginRoot(absolutePath)` + - Call `copyPluginAssets(pluginRoot, bundledDir)` for assets + - Call `copyPluginAssets(pluginRoot, Global.Path.cache)` for runtime resolution parity +- [ ] Add tests in `packages/opencode/test/asset-copy.test.ts`: + - Test audio file copying (`.wav`, `.mp3`, `.ogg`) + - Test nested directory preservation (`sounds/alerts/beep.wav` → `targetDir/sounds/alerts/beep.wav`) + - Test `resolvePluginRoot` with package.json present + - Test `resolvePluginRoot` fallback for single-file plugins (no package.json) + - Test symlink/path traversal entries are skipped + - Test overwrite logging when file already exists + +### Milestone 2: PWA safe area and viewport locking (#264) +- [ ] Reuse `isPWA()` from `packages/app/src/context/platform.tsx` in layout (no new utility file). +- [ ] Add `.home-menu-button` class to menu button in `packages/app/src/pages/home.tsx:35`. +- [ ] Add `data-tauri-drag-region` to the session header in `packages/app/src/components/session/session-header.tsx:52`. +- [ ] Add `.session-scroll-container` class to scroll container in `packages/app/src/pages/session.tsx:906`. +- [ ] Extend PWA CSS rules in `packages/app/src/index.css`: + - `.home-menu-button` top offset + - `.session-scroll-container` overscroll-behavior + - Keep existing `header[data-tauri-drag-region]` safe-area rule +- [ ] Update `packages/app/src/components/pull-to-refresh.tsx` to accept an `enabled` prop and guard refresh behavior. +- [ ] Update `packages/app/src/pages/layout.tsx` to pass `enabled={!isPWA()}` to `PullToRefresh` while preserving the scroll wrapper. +- [ ] Verify `#root`/body sizing still uses `h-dvh` and `min-height` values appropriate for iOS PWA. + +### Milestone 3: Validation and regression checks +- [ ] Run `bun test` in `packages/opencode` (new asset copy tests). +- [ ] Run `bun turbo test` at repo root for full test suite. +- [ ] Manually verify iOS PWA on Dynamic Island device (iPhone 14+). +- [ ] Manually verify iOS PWA on notch device (iPhone X-13). +- [ ] Manually verify Android PWA pull-down behavior in session view. +- [ ] Verify no desktop/browser regressions for menu placement and scrolling. +- [ ] Verify `@mohak34/opencode-notifier` sounds play correctly. + +## Validation Criteria + +### Automated +- `bun test` in `packages/opencode` passes (new asset copy tests). +- `bun turbo test` at repo root passes. +- TypeScript compilation succeeds for both `opencode` and `app` packages. + +### Manual +- `@mohak34/opencode-notifier` plays sounds after bundling with audio assets copied. +- Home and session menu buttons are fully visible below the Dynamic Island in PWA standalone mode. +- Session view does not allow scrolling past content into blank space in PWA standalone mode. +- Android PWA swipe-down does not refresh the page when scrolling back up in session view. +- Non-PWA mobile still scrolls correctly and pull-to-refresh behavior remains unchanged. +- Desktop browser shows no visual regressions in header/menu positioning. + +### Manual Test Steps +```bash +# Issue #266: Plugin asset bundling +# Clear bundled plugin cache for notifier +rm -rf ~/.cache/opencode/bundled/*mohak34* +rm -rf ~/.cache/opencode/bundled-local/* + +# Launch opencode/shuvcode and install notifier plugin +# Trigger notification events and verify sounds play + +# Verify directory structure preserved +ls -la ~/.cache/opencode/bundled/ +# Should show: mohak34-opencode-notifier.js AND sounds/ directory with .wav files +``` + +```bash +# Issue #264: PWA testing +# iOS: Add to Home Screen from Safari, launch as PWA +# - Verify menu button not obscured by Dynamic Island +# - Verify session header not obscured +# - Verify session scroll doesn't overscroll to blank space + +# Android: Add to Home Screen from Chrome, launch as PWA +# - Verify pull-down in session view doesn't trigger refresh +# +# Non-PWA mobile browser: +# - Verify session view still scrolls and pull-to-refresh behavior is unchanged +``` + +## File Changes Summary + +| File | Change Type | Description | +| --- | --- | --- | +| `packages/opencode/src/util/asset-copy.ts` | **NEW** | Shared asset copy utility: `ASSET_EXTENSIONS`, `copyPluginAssets()`, `resolvePluginRoot()` | +| `packages/opencode/src/bun/index.ts` | MODIFY | Import shared utility, remove inline `copyPluginAssets` and `assetExtensions` | +| `packages/opencode/src/plugin/index.ts` | MODIFY | Import `resolvePluginRoot`, call `copyPluginAssets()` after `bundleLocalPlugin()` | +| `packages/opencode/test/asset-copy.test.ts` | **NEW** | Tests for asset copying, directory preservation, plugin root resolution, security | +| `packages/app/src/pages/home.tsx` | MODIFY | Add `.home-menu-button` class | +| `packages/app/src/components/session/session-header.tsx` | MODIFY | Add `data-tauri-drag-region` attribute | +| `packages/app/src/pages/session.tsx` | MODIFY | Add `.session-scroll-container` class | +| `packages/app/src/components/pull-to-refresh.tsx` | MODIFY | Add `enabled` prop, guard touch handlers with early returns | +| `packages/app/src/pages/layout.tsx` | MODIFY | Import `isPWA`, pass `enabled={!isPWA()}` to `PullToRefresh` | +| `packages/app/src/index.css` | MODIFY | Extend PWA-specific CSS rules | + +## Resolved Questions + +| Question | Resolution | +| --- | --- | +| Should audio formats beyond `.wav` be included? | YES - Include `.wav`, `.mp3`, `.ogg`, `.flac`, `.m4a`, `.aac` plus video/font formats | +| Should local `file://` plugins get asset copying? | YES - Share `copyPluginAssets()` between `bun/index.ts` and `plugin/index.ts`, copying from resolved plugin root into `bundled-local` and `Global.Path.cache` | +| How to find plugin root for local plugins? | Walk up from entry file to nearest `package.json`. Fallback to `path.dirname(entryFilePath)` for single-file plugins without package.json | +| PWA styling: inline styles vs CSS utilities? | CSS with `@media (display-mode: standalone)` for maintainability | +| How to detect PWA mode in components? | Reuse existing `isPWA()` from `packages/app/src/context/platform.tsx` | +| Should PullToRefresh keep scroll container when disabled? | YES - Only guard refresh gesture, keep scroll containment for consistent UX | diff --git a/CONTEXT/PLAN-268-askquestion-dialog-fix-2026-01-05.md b/CONTEXT/PLAN-268-askquestion-dialog-fix-2026-01-05.md new file mode 100644 index 00000000000..75991099b3b --- /dev/null +++ b/CONTEXT/PLAN-268-askquestion-dialog-fix-2026-01-05.md @@ -0,0 +1,573 @@ +# Plan: AskQuestion Tool Dialog Fix + +**Issue:** [#268 - AskQuestion tool: Dialog not appearing in Web or TUI mode](https://github.com/Latitudes-Dev/shuvcode/issues/268) + +**Created:** 2026-01-05 + +**Revised:** 2026-01-06 - Added callID validation, sync confirmation recommendations, detection helper extraction + +**Severity:** High - This breaks the core UX of the experimental askquestion feature. + +**Status:** READY TO IMPLEMENT + +--- + +## Overview + +The `askquestion` tool is invoked by the LLM, but the expected wizard dialog does not appear in either Web or TUI mode. The user cannot respond to clarifying questions, causing the tool to hang indefinitely. + +### Configuration Required + +```yaml +# .opencode/config.yaml +experimental: + askquestion_tool: true +``` + +--- + +## Acceptance Criteria + +- [ ] Wizard dialog appears when LLM invokes `askquestion` in **Web mode** +- [ ] Wizard dialog appears when LLM invokes `askquestion` in **TUI mode** +- [ ] User can submit answers via the wizard +- [ ] User can cancel the wizard with Escape +- [ ] Tool resumes correctly after user response +- [ ] Comprehensive end-to-end tests exist proving the full flow works + +--- + +## Architecture Reference + +### Component Map + +| Layer | File | Purpose | +|-------|------|---------| +| Tool Definition | `packages/opencode/src/tool/askquestion.ts` | Defines tool schema, registers pending request, awaits response | +| State Management | `packages/opencode/src/askquestion/index.ts` | `register()`, `respond()`, `cancel()`, `cleanup()` functions | +| Server Endpoints | `packages/opencode/src/server/server.ts:1694-1763` | `POST /askquestion/respond` and `/askquestion/cancel` | +| Web App Detection | `packages/app/src/pages/session.tsx:240-288` | `pendingAskQuestion` memo + handlers | +| Web App UI | `packages/app/src/components/askquestion-wizard.tsx` | `AskQuestionWizard` Solid.js component | +| Web App Rendering | `packages/app/src/pages/session.tsx:993-1010` | Conditional render of wizard vs prompt input | +| TUI Detection | `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx:391-418` | `pendingAskQuestionFromSync` memo | +| TUI UI | `packages/opencode/src/cli/cmd/tui/ui/dialog-askquestion.tsx` | `DialogAskQuestion` component | +| TUI Rendering | `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx:1447-1489` | Switch/Match conditional rendering | +| Tool Context | `packages/opencode/src/session/prompt.ts:662-677` | `ctx.metadata()` implementation | +| Part Sync | `packages/opencode/src/session/index.ts:391-401` | `updatePart()` publishes `PartUpdated` event | +| Existing Tests | `packages/opencode/test/tool/askquestion.test.ts` | Core promise flow + detection logic mocks | + +### Expected Data Flow + +``` +1. LLM calls askquestion tool with questions array + └─> askquestion.ts:19-28 + +2. Tool calls await ctx.metadata({ status: "waiting", questions }) + └─> prompt.ts:662-677 -> Session.updatePart() + └─> session/index.ts:391-401 -> Bus.publish(PartUpdated) + +3. SSE delivers PartUpdated event to clients + └─> server.ts:173-209 (global event stream) + +4. Client detects pending askquestion via sync.data.part + └─> Web: session.tsx:240-268 (pendingAskQuestion memo) + └─> TUI: session/index.tsx:391-418 (pendingAskQuestionFromSync memo) + +5. Client renders wizard dialog + └─> Web: session.tsx:993-1010 (AskQuestionWizard) + └─> TUI: session/index.tsx:1448-1484 (DialogAskQuestion) + +6. User submits answers + └─> POST /askquestion/respond -> server.ts:1694-1728 + └─> AskQuestion.respond() resolves the promise + +7. Tool promise resolves, returns formatted answers to LLM + └─> askquestion.ts:46-77 +``` + +--- + +## Suspected Root Causes + +### 1. Sync/Reactivity Gap (Most Likely) + +**Hypothesis:** The `ctx.metadata()` call updates the part and publishes `PartUpdated`, but the SSE sync may not deliver the updated part state to the client before the detection logic runs. + +**Evidence:** +- `ctx.metadata()` is async and awaited (`askquestion.ts:22`) +- `Session.updatePart()` publishes to Bus, which SSE listens to +- But there's no explicit "wait for sync" mechanism + +**Location:** `packages/opencode/src/session/prompt.ts:662-677` + +**Review Finding:** The `ctx.metadata()` at `prompt.ts:665-676` does await `Session.updatePart()`, but this only ensures the local state is updated. SSE delivery to clients is asynchronous and not confirmed. + +**Mitigation Options:** +1. **Small delay after metadata update** (simplest): + ```ts + await ctx.metadata({ ... }) + await new Promise(resolve => setTimeout(resolve, 50)) // Allow SSE delivery + ``` +2. **Use dedicated Bus event** - `AskQuestion.Event.Requested` already exists at `askquestion/index.ts:44-52` but is not currently published. Clients could listen for this instead of polling part state. +3. **Polling/retry in client detection** - If first check fails, retry a few times with small delays. + +### 2. Part State Structure Mismatch + +**Hypothesis:** The detection logic expects `part.state.metadata.status === "waiting"`, but the actual synced structure may differ. + +**Evidence:** +- Tool sets: `metadata: { questions, status: "waiting" }` (`askquestion.ts:24-27`) +- Detection checks: `part.state.metadata?.status !== "waiting"` (`session.tsx:257`) +- The `ToolStateRunning` schema shows `metadata: z.record(z.string(), z.any()).optional()` (`message-v2.ts:244`) + +**Location:** `packages/opencode/src/session/message-v2.ts:239-252` + +### 3. callID Undefined + +**Hypothesis:** The `ctx.callID` may be undefined when the tool is invoked. + +**Evidence:** +- Tool uses `ctx.callID!` (non-null assertion) at `askquestion.ts:32,40` +- Tool.Context defines `callID?: string` (optional) at `tool.ts:20` + +**Location:** `packages/opencode/src/tool/askquestion.ts:32` + +**Risk Assessment (from review):** Low risk - `callID` comes from `options.toolCallId` in `prompt.ts:659` which is set by the AI SDK for all tool calls. However, defensive validation should be added. + +**Required Fix:** Add explicit validation at the start of execute(): +```ts +async execute(params, ctx) { + if (!ctx.callID) { + throw new Error("callID is required for askquestion tool") + } + // ... rest of implementation +} +``` + +### 4. Switch/Match Ordering (TUI Only) + +**Hypothesis:** If another condition matches first (e.g., permissions), the dialog won't show. + +**Evidence:** +- Current order at `session/index.tsx:1447-1509`: + 1. `pendingAskQuestionFromSync()` - DialogAskQuestion + 2. `permissions().length > 0` - PermissionPrompt + 3. `searchMode()` - SearchInput + 4. Default - Prompt + +**Assessment:** This ordering is correct (askquestion first), so unlikely to be the issue. + +--- + +## Implementation Tasks + +### Phase 0: Required Fix (Pre-Investigation) + +- [ ] **0.1** Add callID validation to `askquestion.ts` execute function + - File: `packages/opencode/src/tool/askquestion.ts:19` + - Add at start of execute(): + ```ts + if (!ctx.callID) { + throw new Error("callID is required for askquestion tool") + } + ``` + - Remove non-null assertions (`!`) at lines 32 and 40, replace with direct `ctx.callID` usage + +### Phase 1: Investigation & Debugging + +- [ ] **1.1** Add debug logging to `askquestion.ts` after `ctx.metadata()` call to verify it returns + - File: `packages/opencode/src/tool/askquestion.ts:28` + - Add: `console.log("[askquestion] metadata updated, callID:", ctx.callID)` + +- [ ] **1.2** Add debug logging to Web detection memo to see what parts are being scanned + - File: `packages/app/src/pages/session.tsx:240-268` + - Add console.log for each part checked, especially tool parts + +- [ ] **1.3** Add debug logging to TUI detection memo + - File: `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx:391-418` + - Add console.log for each part checked + +- [ ] **1.4** Verify SSE delivers the `PartUpdated` event with correct structure + - Use browser DevTools to inspect SSE events + - Check that `part.state.metadata.status === "waiting"` is present + +- [ ] **1.5** Verify `ctx.callID` is defined when `askquestion` tool executes + - File: `packages/opencode/src/session/prompt.ts:659` + - Log the `options.toolCallId` value + +### Phase 2: Fix Sync/Reactivity Issues + +Based on investigation results, one or more of these may be needed: + +- [ ] **2.1** Ensure `ctx.metadata()` properly awaits sync propagation + - File: `packages/opencode/src/session/prompt.ts:662-677` + - Current implementation awaits `Session.updatePart()` - this is correct + - Verify the async function is properly awaited before returning + +- [ ] **2.2** Add explicit sync wait after metadata update (if needed) + - File: `packages/opencode/src/tool/askquestion.ts:28` + - Option A (simple): Add 50ms delay after metadata update to allow SSE delivery + - Option B (robust): Publish `AskQuestion.Event.Requested` via Bus and have clients listen for it + - Option C (client-side): Add retry logic to client detection memos + +- [ ] **2.3** (DONE in Phase 0) callID validation added to tool execute function + +### Phase 3: Fix Detection Logic (If Needed) + +- [ ] **3.1** Verify `toolPart.callID` is available (not undefined) in detection + - File: `packages/app/src/pages/session.tsx:260` + - File: `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx:409` + +- [ ] **3.2** Verify `toolPart.state.metadata` type matches expected schema + - Ensure detection correctly extracts `{ status, questions }` from metadata + +- [ ] **3.3** Consider alternative detection using `AskQuestion.getForSession()` directly + - This would bypass sync reactivity issues + - Would require server endpoint to expose pending requests + +### Phase 4: Comprehensive Testing + +#### 4.1 Server Endpoint Integration Tests + +- [ ] **4.1.1** Create test file: `packages/opencode/test/server/askquestion.test.ts` + +```typescript +// packages/opencode/test/server/askquestion.test.ts +import { describe, expect, test, beforeEach, afterEach } from "bun:test" +import { AskQuestion } from "../../src/askquestion" +import { Server } from "../../src/server/server" +import { Instance } from "../../src/project/instance" + +describe("askquestion server endpoints", () => { + test("POST /askquestion/respond resolves pending request", async () => { + await Instance.provide({ + directory: process.cwd(), + fn: async () => { + const server = Server.create() + const callID = "test-call-123" + const sessionID = "test-session" + const messageID = "test-message" + + // Register pending request + const promise = AskQuestion.register(callID, sessionID, messageID, [ + { id: "q1", label: "Q1", question: "Pick one", options: [ + { value: "a", label: "A" }, + { value: "b", label: "B" }, + ]}, + ]) + + // Simulate client response + const res = await server.request("/askquestion/respond", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + callID, + sessionID, + answers: [{ questionId: "q1", values: ["a"] }], + }), + }) + + expect(res.status).toBe(200) + const answers = await promise + expect(answers[0].values).toEqual(["a"]) + }, + }) + }) + + test("POST /askquestion/cancel rejects pending request", async () => { + await Instance.provide({ + directory: process.cwd(), + fn: async () => { + const server = Server.create() + const callID = "test-call-456" + const sessionID = "test-session" + const messageID = "test-message" + + const promise = AskQuestion.register(callID, sessionID, messageID, [ + { id: "q1", label: "Q1", question: "Pick one", options: [ + { value: "a", label: "A" }, + ]}, + ]) + + const res = await server.request("/askquestion/cancel", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ callID, sessionID }), + }) + + expect(res.status).toBe(200) + await expect(promise).rejects.toThrow("User cancelled") + }, + }) + }) + + test("POST /askquestion/respond returns 404 for unknown callID", async () => { + await Instance.provide({ + directory: process.cwd(), + fn: async () => { + const server = Server.create() + + const res = await server.request("/askquestion/respond", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + callID: "nonexistent", + sessionID: "test-session", + answers: [], + }), + }) + + expect(res.status).toBe(500) // Will throw error internally + }, + }) + }) +}) +``` + +#### 4.2 Sync Propagation Tests + +- [ ] **4.2.1** Create test for part sync after metadata update + +```typescript +// packages/opencode/test/tool/askquestion-sync.test.ts +import { describe, expect, test } from "bun:test" +import { Session } from "../../src/session" +import { MessageV2 } from "../../src/session/message-v2" +import { Bus } from "../../src/bus" +import { Instance } from "../../src/project/instance" + +describe("AskQuestion Sync Propagation", () => { + test("metadata update publishes PartUpdated event with correct structure", async () => { + await Instance.provide({ + directory: process.cwd(), + fn: async () => { + const events: any[] = [] + const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, (evt) => { + events.push(evt) + }) + + const part: MessageV2.ToolPart = { + id: "part-123", + sessionID: "session-123", + messageID: "message-123", + type: "tool", + tool: "askquestion", + callID: "call-123", + state: { + status: "running", + input: {}, + time: { start: Date.now() }, + metadata: { + status: "waiting", + questions: [{ id: "q1", label: "Q1", question: "Test?", options: [] }], + }, + }, + } + + await Session.updatePart(part) + + expect(events.length).toBe(1) + expect(events[0].part.state.metadata.status).toBe("waiting") + expect(events[0].part.state.status).toBe("running") + + unsub() + }, + }) + }) +}) +``` + +#### 4.3 Detection Logic Tests + +- [ ] **4.3.1** Add tests for detection edge cases + +```typescript +// packages/opencode/test/tool/askquestion.test.ts (extend existing) + +describe("AskQuestion Detection Edge Cases", () => { + test("detects pending when callID is present", () => { + const messages = [{ id: "m1" }] + const partsMap = { + m1: [ + { + type: "tool", + tool: "askquestion", + callID: "call-123", // Important: callID must be present + state: { + status: "running", + metadata: { status: "waiting", questions: [] }, + }, + }, + ], + } + const result = detectPending(messages, partsMap) + expect(result).not.toBeNull() + expect(result?.callID).toBe("call-123") + }) + + test("returns null when callID is undefined", () => { + const messages = [{ id: "m1" }] + const partsMap = { + m1: [ + { + type: "tool", + tool: "askquestion", + callID: undefined, // Missing callID + state: { + status: "running", + metadata: { status: "waiting", questions: [] }, + }, + }, + ], + } + const result = detectPending(messages, partsMap) + // Should this return null or handle gracefully? + expect(result?.callID).toBeUndefined() + }) + + test("ignores when part.state.status is not 'running'", () => { + const messages = [{ id: "m1" }] + const partsMap = { + m1: [ + { + type: "tool", + tool: "askquestion", + callID: "call-123", + state: { + status: "pending", // Not running + metadata: { status: "waiting", questions: [] }, + }, + }, + ], + } + const result = detectPending(messages, partsMap) + expect(result).toBeNull() + }) + + test("ignores when metadata.status is 'completed'", () => { + const messages = [{ id: "m1" }] + const partsMap = { + m1: [ + { + type: "tool", + tool: "askquestion", + callID: "call-123", + state: { + status: "running", + metadata: { status: "completed", answers: [] }, + }, + }, + ], + } + const result = detectPending(messages, partsMap) + expect(result).toBeNull() + }) +}) +``` + +#### 4.4 Session Abort Cleanup Tests + +- [ ] **4.4.1** Add test for cleanup on session abort + +```typescript +describe("AskQuestion Cleanup", () => { + test("cleanup rejects all pending requests for session", async () => { + const sessionID = "session-to-abort" + const promises = [] + + for (let i = 0; i < 3; i++) { + promises.push( + AskQuestion.register(`call-${i}`, sessionID, `msg-${i}`, []) + ) + } + + AskQuestion.cleanup(sessionID) + + for (const promise of promises) { + await expect(promise).rejects.toThrow("Session aborted") + } + }) +}) +``` + +### Phase 5: Manual Validation + +- [ ] **5.1** Test in TUI mode + - Start shuvcode in TUI + - Enable `experimental.askquestion_tool: true` + - Trigger LLM to use askquestion (e.g., "Help me choose a database") + - Verify dialog appears + - Test submit and cancel + +- [ ] **5.2** Test in Web mode + - Start shuvcode server + - Open web app + - Enable `experimental.askquestion_tool: true` + - Trigger LLM to use askquestion + - Verify wizard appears + - Test submit and cancel on desktop + - Test submit and cancel on mobile viewport + +- [ ] **5.3** Test edge cases + - Multiple questions in sequence + - Cancel mid-flow + - Session abort while question pending + - Custom text response + +--- + +## External References + +- **Solid.js Reactivity:** https://www.solidjs.com/docs/latest/api#creatememo +- **Hono SSE Streaming:** https://hono.dev/helpers/streaming#sse-stream +- **Bun Test:** https://bun.sh/docs/cli/test + +--- + +## File Modifications Summary + +| File | Action | Description | +|------|--------|-------------| +| `packages/opencode/src/tool/askquestion.ts` | Modify | Add callID validation, remove non-null assertions, add debug logging | +| `packages/opencode/src/session/prompt.ts` | Modify | Verify metadata sync (may add delay or event publish) | +| `packages/app/src/pages/session.tsx` | Modify | Add debug logging for detection (temporary) | +| `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` | Modify | Add debug logging for detection (temporary) | +| `packages/opencode/test/server/askquestion.test.ts` | Create | Server endpoint tests | +| `packages/opencode/test/tool/askquestion.test.ts` | Modify | Add edge case tests, callID validation test | + +--- + +## Definition of Done + +1. All acceptance criteria checkboxes are checked +2. All new tests pass (`bun turbo test`) +3. TypeScript compiles without errors for both `opencode` and `app` packages +4. Manual validation passes in both TUI and Web modes +5. Debug logging is removed before merge +6. PR is reviewed and approved + +--- + +## Risks & Mitigations + +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|------------| +| SSE timing issues in production | Medium | High | Add explicit sync confirmation mechanism | +| Breaking other tool metadata flows | Low | High | Comprehensive test coverage | +| Mobile-specific issues | Medium | Medium | Explicit mobile testing in validation | + +--- + +## Notes + +- The detection logic is duplicated between Web (`session.tsx:240-268`) and TUI (`session/index.tsx:391-418`) - consider extracting to shared utility after fix is confirmed +- The `ctx.callID!` non-null assertion is addressed in Phase 0 with explicit validation +- The tool is behind `experimental.askquestion_tool` flag, so production impact is limited to opt-in users +- The `detectPending` helper function referenced in test examples (Phase 4.3) does not exist - it represents the extracted detection logic that should be created as part of the refactor + +## Post-Fix Refactoring (Optional) + +After the fix is confirmed working, consider: +1. Extract `detectPendingAskQuestion(messages, parts)` to `packages/opencode/src/askquestion/detect.ts` +2. Share detection logic between Web and TUI +3. Publish `AskQuestion.Event.Requested` from tool for more reliable client notification diff --git a/CONTEXT/PLAN-269-tui-transparency-toggle-2026-01-06.md b/CONTEXT/PLAN-269-tui-transparency-toggle-2026-01-06.md new file mode 100644 index 00000000000..4759d96e7bc --- /dev/null +++ b/CONTEXT/PLAN-269-tui-transparency-toggle-2026-01-06.md @@ -0,0 +1,244 @@ +# Plan: TUI Transparency Toggle Fix + +**Issue:** [#269 - Transparency toggle ignored; TUI background stays transparent across themes](https://github.com/Latitudes-Dev/shuvcode/issues/269) + +**Created:** 2026-01-06 + +**Revised:** 2026-01-06 - Critical fix: Target `resolveColor` or post-resolution normalization, not just `resolveTheme`. Added fallback chain for themes with all-transparent backgrounds. + +**Status:** NEEDS REVISION BEFORE IMPLEMENTATION + +## Overview +The TUI transparency toggle currently does not restore opaque backgrounds. The fix must ensure `theme_transparent=false` renders opaque backgrounds for all built-in themes, while `theme_transparent=true` enforces transparent backgrounds. The toggle must update the runtime theme immediately, persist across restart, and keep selected list item contrast readable. + +## Critical Issue Identified in Review + +**Root Cause:** The plan's original approach is incorrect. The current `resolveTheme` at line 226-230 only forces transparency when `transparent=true`. It does NOT force opacity when `transparent=false`. + +The real issue is that themes like `lucent-orng` use `"transparent"` as a literal color value in the JSON: +```json +"background": { "dark": "transparent", "light": "transparent" } +``` + +The `resolveColor` function at `theme.tsx:180` converts `"transparent"` to `RGBA(0,0,0,0)` **BEFORE** `resolveTheme` can apply any toggle override. By the time `resolveTheme` checks `if (transparent)`, the damage is done. + +## Requirements (from issue) +- [ ] `theme_transparent=false` renders opaque backgrounds for all built-in themes. +- [ ] `theme_transparent=true` renders transparent backgrounds consistently. +- [ ] Toggling the command updates the runtime theme immediately and persists across restart. +- [ ] Selected list item contrast stays readable when transparency is off. + +## Current Code Context +### Observations +- `resolveTheme` forces `background` alpha to 0 when `transparent` is true. +- `resolveColor` maps "transparent" or "none" to RGBA(0,0,0,0) regardless of toggle state. +- `selectedForeground` uses `theme.background.a === 0` to compute selected list item text color. +- Theme state is stored in KV using `theme_transparent` and read into `store.transparent` via `useKV`. +- Built-in theme `lucent-orng` contains "transparent" values, which can produce alpha 0 even when the toggle is off. + +### Internal References +| Area | File | Notes | +| --- | --- | --- | +| Toggle command | `packages/opencode/src/cli/cmd/tui/app.tsx` | "Toggle transparency" invokes `setTransparent(!transparent())`. | +| Theme resolution | `packages/opencode/src/cli/cmd/tui/context/theme.tsx:175-238` | `resolveTheme` function - add normalization here. | +| Color resolution | `packages/opencode/src/cli/cmd/tui/context/theme.tsx:177-196` | `resolveColor` converts "transparent" to alpha=0 - DO NOT MODIFY. | +| Selected foreground | `packages/opencode/src/cli/cmd/tui/context/theme.tsx:106-121` | `selectedForeground` checks `background.a === 0` - will auto-correct after normalization. | +| Theme persistence | `packages/opencode/src/cli/cmd/tui/context/theme.tsx:294,396-398` | `kv.get("theme_transparent", false)` and `kv.set("theme_transparent", transparent)`. | +| Built-in theme | `packages/opencode/src/cli/cmd/tui/context/theme/lucent-orng.json:64-79` | Uses "transparent" values for all backgrounds except `backgroundMenu`. | + +### Configuration Values +| Key | Location | Purpose | Type | +| --- | --- | --- | --- | +| `theme_transparent` | KV store | Persist transparency toggle | boolean | +| `theme` | KV store / sync config | Active theme name | string | +| `theme_mode` | KV store | Light/dark mode | "light" or "dark" | + +## Technical Approach and Decisions +### Hypotheses to Validate +- `store.transparent` is stuck `true` due to persistence or rehydration issues. +- Theme JSON values set to "transparent" are overriding the toggle when `transparent=false`. **CONFIRMED** +- Theme recomputation is not re-running after toggling. + +### Root Cause (Confirmed) +The `resolveColor` function at `theme.tsx:180` maps `"transparent"` or `"none"` strings to `RGBA(0,0,0,0)` **regardless of the toggle state**. This happens during color resolution, before `resolveTheme` can apply the `transparent` parameter. + +### Decision (Revised) +Add a **post-resolution normalization step** that enforces opaque backgrounds when `transparent=false`: +- When `transparent=true`, backgrounds should be fully transparent (current behavior). +- When `transparent=false`, ANY background color with alpha=0 should be replaced with an opaque fallback. +- Fallback chain: `background` → `backgroundPanel` → `backgroundElement` → `backgroundMenu` → derive from `primary`. + +Rationale: The acceptance criteria requires opaque backgrounds for all built-in themes when transparency is off. The normalization must happen AFTER `resolveColor` has processed all values. + +### Option Comparison (Updated) +| Option | Summary | Pros | Cons | Decision | +| --- | --- | --- | --- | --- | +| Pass `transparent` to `resolveColor` | Make color resolution aware of toggle | Early fix | Requires threading parameter through all calls | Rejected (too invasive) | +| **Post-resolution normalization** | Add step after all colors resolved to enforce opacity | Central fix, doesn't modify resolveColor | Requires fallback color logic | **Selected** | +| Edit theme JSONs | Replace "transparent" values with opaque colors per theme | Simple to reason about per theme | Breaks custom themes and user overrides | Rejected | +| Add per-theme allowlist | Allow only specific themes to stay transparent | Fine-grained | Contradicts acceptance criteria | Rejected | + +## Technical Specifications + +### Opaque Fallback Rules +Add a normalization function called AFTER all colors are resolved but BEFORE returning the theme: + +```ts +// In theme.tsx, after resolveTheme builds the resolved object + +function normalizeBackgrounds(resolved: Partial, transparent: boolean): Partial { + if (transparent) return resolved // No normalization when transparency is on + + // Find first opaque background to use as fallback + const findOpaqueFallback = (): RGBA => { + // Fallback chain: backgroundMenu → backgroundElement → backgroundPanel → derive from primary + const candidates = [ + resolved.backgroundMenu, + resolved.backgroundElement, + resolved.backgroundPanel, + resolved.background, + ] + + for (const color of candidates) { + if (color && color.a > 0) return color + } + + // Last resort: derive dark background from primary + // Use primary at 10% luminance for dark themes, 95% for light + const primary = resolved.primary! + return RGBA.fromInts( + Math.round(primary.r * 0.1 * 255), + Math.round(primary.g * 0.1 * 255), + Math.round(primary.b * 0.1 * 255), + 255 // Fully opaque + ) + } + + const fallback = findOpaqueFallback() + + // Replace any transparent backgrounds with the fallback + const backgroundFields: (keyof ThemeColors)[] = [ + 'background', 'backgroundPanel', 'backgroundElement', 'backgroundMenu' + ] + + for (const field of backgroundFields) { + const color = resolved[field] + if (color && color.a === 0) { + resolved[field] = fallback + } + } + + return resolved +} +``` + +### Integration Point +In `resolveTheme` function (`theme.tsx:175`), call normalization AFTER resolution but BEFORE returning: + +```ts +function resolveTheme(theme: ThemeJson, mode: "dark" | "light", transparent: boolean) { + // ... existing resolution logic (lines 176-230) ... + + // NEW: Normalize backgrounds when transparency is off + const normalized = normalizeBackgrounds(resolved, transparent) + + return { + ...normalized, + _hasSelectedListItemText: hasSelectedListItemText, + thinkingOpacity, + transparent, + } as Theme +} +``` + +### Impacted Colors +These fields are normalized when alpha is 0 and `transparent=false`: +- `background` - main app background +- `backgroundPanel` - panel/sidebar backgrounds +- `backgroundElement` - element backgrounds (inputs, buttons) +- `backgroundMenu` - menu/dropdown backgrounds + +### Selected List Item Contrast +The `selectedForeground` function at `theme.tsx:106-121` checks `theme.background.a === 0` to determine contrast mode: +- After normalization, `background.a` will be `1` (opaque) when `transparent=false` +- This means selected list items will use `theme.background` as foreground (correct behavior) +- No changes needed to `selectedForeground` - it will automatically behave correctly after normalization + +### lucent-orng Theme Analysis +This theme is the primary test case. Current values: +- `background`: `"transparent"` (dark/light) → alpha=0 +- `backgroundPanel`: `"transparent"` → alpha=0 +- `backgroundElement`: `"transparent"` → alpha=0 +- `backgroundMenu`: `"darkPanelBg"` / `"lightPanelBg"` → **opaque!** (`#2a1a1599` has alpha) + +Wait, `#2a1a1599` is a hex color with alpha. Let me check: +- `#2a1a1599` = RGB(42, 26, 21) with alpha 0x99 = 153/255 ≈ 60% opacity + +So `backgroundMenu` is semi-transparent, not fully opaque. The fallback chain must handle this: +- If ALL backgrounds have alpha < 1, derive from primary as last resort + +## Implementation Plan + +### Milestone 1: Reproduce and Inspect State +- [ ] Reproduce in TUI and log `transparent()` before and after toggling. +- [ ] Verify `kv.get("theme_transparent", false)` changes and persists across restart. +- [ ] Inspect `resolveTheme` output for `background.a` with multiple themes (Night Owl, Nord, lucent-orng). +- [ ] Confirm that the theme memo re-runs on `setTransparent` by logging `store.transparent` and `values().background.a`. +- [ ] **NEW:** Verify that `lucent-orng` theme resolves to alpha=0 even when toggle is off (confirms root cause). + +### Milestone 2: Fix Theme Resolution +- [ ] Create `normalizeBackgrounds(resolved, transparent)` helper function in `theme.tsx`. +- [ ] Implement fallback chain: `backgroundMenu` → `backgroundElement` → `backgroundPanel` → derive from `primary`. +- [ ] Handle semi-transparent colors (e.g., `#2a1a1599` with alpha=0x99) - require full opacity (alpha=1) for fallback. +- [ ] Call `normalizeBackgrounds()` at the end of `resolveTheme()` before returning. +- [ ] Ensure the `theme.transparent` flag reflects the toggle state correctly. + +### Milestone 3: Contrast and Theme UX +- [ ] Re-validate `selectedForeground` behavior with opaque backgrounds. +- [ ] Verify that selected list item contrast remains readable for Night Owl, Nord, opencode, and lucent-orng themes. +- [ ] **NEW:** Test with light mode themes to ensure derived fallback works for both dark and light modes. + +### Milestone 4: Tests +- [ ] Add unit tests in `packages/opencode/test/theme.test.ts` for: + - `normalizeBackgrounds` with fully transparent theme + - `normalizeBackgrounds` with semi-transparent `backgroundMenu` + - `normalizeBackgrounds` fallback derivation from `primary` + - Full `resolveTheme` with `transparent=false` and lucent-orng fixture +- [ ] Add test for `selectedForeground` to verify readable contrast when transparency is off. + +### Milestone 5: Manual Validation +- [ ] Toggle transparency on/off in TUI and verify immediate updates. +- [ ] Switch themes (Night Owl, Nord, lucent-orng) and verify backgrounds are opaque when toggle is off. +- [ ] Restart TUI and confirm the last toggle state is restored. +- [ ] **NEW:** Test lucent-orng specifically in both dark and light modes with transparency off. + +## Validation Criteria +### Automated +- [ ] `bun test` in `packages/opencode` passes. +- [ ] Theme transparency tests cover both on and off cases. + +### Manual +- [ ] With `theme_transparent=false`, background is opaque for all built-in themes. +- [ ] With `theme_transparent=true`, background is fully transparent. +- [ ] Selected list item text remains readable when transparency is off. +- [ ] Toggle state persists after restart. + +### Suggested Commands +```bash +cd /home/shuv/repos/worktrees/shuvcode/shuvcode-dev/packages/opencode +bun test +``` + +## External References (Git URLs) +- https://github.com/tauri-apps/wry/blob/dev/examples/transparent.rs +- https://github.com/tauri-apps/tao/blob/dev/examples/transparent.rs +- https://raw.githubusercontent.com/electron/electron/main/docs/api/browser-window.md + +## Risks and Mitigations +| Risk | Impact | Mitigation | +| --- | --- | --- | +| Opaque fallback picks a poor color for transparent themes | Medium | Use fallback chain to find best available opaque color; derive from primary as last resort. | +| Derived primary fallback looks bad | Medium | Use 10% luminance of primary for dark mode, 95% for light mode to ensure sufficient contrast. | +| Fix changes behavior for custom themes | Medium | Gate fallback only when `transparent=false` and alpha is 0. Custom themes with explicit opaque colors are unaffected. | +| Contrast regressions on selected items | Medium | Add tests for `selectedForeground` and manual spot checks. The function auto-corrects based on final `background.a`. | +| Semi-transparent backgrounds (e.g., 60% alpha) not handled | Low | Require full opacity (alpha=1) for fallback eligibility; semi-transparent stays as-is or falls through to derived. | diff --git a/CONTEXT/PLAN-270-tui-bash-spinner-stop-2026-01-06.md b/CONTEXT/PLAN-270-tui-bash-spinner-stop-2026-01-06.md new file mode 100644 index 00000000000..8654a600754 --- /dev/null +++ b/CONTEXT/PLAN-270-tui-bash-spinner-stop-2026-01-06.md @@ -0,0 +1,166 @@ +# Plan: TUI Bash Spinner Stops on Completion + +**Issue:** [#270 - Fix TUI tool spinner never stops after command completion](https://github.com/Latitudes-Dev/shuvcode/issues/270) + +**Created:** 2026-01-06 + +**Revised:** 2026-01-06 - Critical correction: Original hypothesis about metadata overwrites is incorrect. The guard already exists at `prompt.ts:664`. Investigation should focus on TUI reactivity chain, not metadata updates. + +**Status:** REVISED - INCORPORATES CODEBASE FINDINGS + +## Overview +The TUI Bash tool spinner continues animating after a command completes. The UI hides the spinner only when the tool part status is no longer `running`, so the plan focuses on ensuring the Bash tool part transitions to `completed` or `error` and that the TUI properly reacts to state changes. + +## Requirements (from issue) +- [ ] Spinner disappears when tool part status transitions to `completed` or `error`. +- [ ] Bash tool parts move out of `running` state once the command exits. +- [ ] No lingering spinner in transcript/history after completion. + +## Current Code Context +### Observations +- The Bash spinner uses a non-reactive constant `isRunning = props.part.state.status === "running"` in the session view; this can stay stale after updates. +- The Bash tool streams output via `ctx.metadata` asynchronously while the process is running. +- `SessionProcessor` updates tool parts to `completed` or `error` on tool-result/tool-error events. +- `ctx.metadata` in the prompt pipeline rewrites state with `status: "running"` and `time.start`. The guard checks in-memory toolcalls, but late metadata can still race with persisted updates if the entry has not been cleared yet. + +### Internal References +| Area | File | Notes | +| --- | --- | --- | +| Bash spinner state | `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx:2088-2152` | `isRunning` is a non-reactive const; `Show when={isRunning}`. | +| Tool status transitions | `packages/opencode/src/session/processor.ts:171-209` | Sets tool part to `completed` on tool-result, `error` on tool-error. | +| Metadata guard + overwrite risk | `packages/opencode/src/session/prompt.ts:662-676` | Guard checks toolcalls entry; `ctx.metadata` rewrites status to `running`. | +| Bash tool execution | `packages/opencode/src/tool/bash.ts:201-217` | Streams output via `ctx.metadata` (fire-and-forget). | +| Bash tool return | `packages/opencode/src/tool/bash.ts:293-300` | Returns `{ title, metadata, output }` triggering tool-result. | +| Event definition | `packages/opencode/src/session/message-v2.ts:419-425` | Event name is `message.part.updated`. | +| Session updatePart publish | `packages/opencode/src/session/index.ts:391-399` | Publishes `MessageV2.Event.PartUpdated`. | +| TUI sync context | `packages/opencode/src/cli/cmd/tui/context/sync.tsx:112-249` | Handles `message.part.updated` events into store. | +| Spinner frames | `packages/opencode/src/cli/cmd/tui/util/spinners.ts` | Provides `getSpinnerFrame()` used by TUI. | + +## Technical Approach and Decisions +### Hypotheses to Validate + +**Hypothesis 1: tool-result not emitted** (Unlikely) +- The tool-result event is not emitted for Bash tool executions, so status never reaches `completed`. +- **Assessment:** Bash tool returns via `return { title, metadata, output }` at `bash.ts:293-300`, which should trigger tool-result in the AI SDK. + +**Hypothesis 2: non-reactive spinner state** (Likely) +- `isRunning` is a non-reactive const in the Bash component; it can remain `true` after status updates. + +**Hypothesis 3: metadata overwrites** (Possible - guard not sufficient) +- `ctx.metadata` rewrites status to `running`. The guard only checks the in-memory toolcalls entry; late metadata can still race with persisted `completed` updates. + +**Hypothesis 4: TUI reactivity gap / event delivery** (Possible) +- The completion update is emitted but not reflected in the TUI due to sync or rendering issues. +- Solid.js reactivity chain: `sync.data.part[messageID]` → component props → `isRunning` derivation +- Event name is `message.part.updated`; confirm the stream delivers it. + +**Hypothesis 5: Part lookup mismatch** (Possible) +- The TUI looks up parts by `messageID` but the spinner component receives the wrong part reference. +- Need to verify TUI part lookup matches the part being updated. + +### Decision (Revised) +Prioritize the **non-reactive spinner state** and validate ordering/race conditions: +1. Confirm `isRunning` is non-reactive in the Bash component and fix it if so. +2. Verify tool-result fires and `Session.updatePart` is called with `status: "completed"`. +3. Validate whether late `ctx.metadata` calls can regress the persisted status. +4. Verify the event stream (`message.part.updated`) reaches the TUI sync store. + +### Option Comparison (Revised) +| Option | Summary | Pros | Cons | Decision | +| --- | --- | --- | --- | --- | +| Fix Bash spinner reactivity | Make `isRunning` reactive (memo or inline check) | Directly addresses likely root cause | Requires UI change only | **Primary fix** | +| Guard against status regression | Prevent `completed`/`error` -> `running` writes | Eliminates race risk | Needs careful invariants | Secondary if race confirmed | +| Verify event delivery | Confirm `message.part.updated` events reach sync store | Confirms data path | Diagnostic only | Diagnostic step | +| Fix part lookup mismatch | Ensure spinner uses updated part instance | Resolves mismatched references | Less likely | Triage if needed | +| Add timeout-based spinner hide | Hide spinner after N seconds regardless of status | Simple workaround | Masks underlying bug | Rejected | + +## Technical Specifications +### Tool Part Status Flow +- Initial tool part state: `running`. +- Completion: `completed` with `time.end`, `metadata`, `output`. +- Failure: `error` with `time.end` and error message. + +### Bash Tool Metadata Schema +- `metadata.output`: raw output (possibly truncated). +- `metadata.description`: user-provided description. +- `metadata.exit`: process exit code (final result). + +### UI Behavior +- Spinner visible only when `props.part.state.status === "running"`. + +## Implementation Plan + +### Milestone 1: Reproduce and Trace State Transitions +- [ ] Reproduce in TUI and confirm the Bash part status after command completion (server-side). +- [ ] Inspect `Bash` component `isRunning` for reactivity; convert to `createMemo` or inline reactive check if stale. +- [ ] Add logging to `processor.ts:171-191` (tool-result case) to verify it fires for Bash tool. +- [ ] Add logging to `Session.updatePart` to confirm it's called with `status: "completed"`. +- [ ] Log when `ctx.metadata` attempts to write after completion (guarded and unguarded cases). + +### Milestone 2: Trace Event Delivery and Store Updates +- [ ] Add logging to TUI sync handler when `message.part.updated` is received. +- [ ] Add logging when `sync.data.part[messageID]` is updated in the store. +- [ ] Identify the TUI component that renders the Bash spinner and trace its props/derivations. +- [ ] Confirm the component re-renders on part status change (post `isRunning` fix). + +### Milestone 3: Fix Based on Findings +Based on investigation, the fix will be one or more of: +- [ ] Fix Bash spinner reactivity (`isRunning` as memo or inline check). +- [ ] **If metadata regression confirmed:** Prevent `completed`/`error` → `running` writes (guard in `Session.updatePart` or `ctx.metadata`). +- [ ] **If event not delivering:** Fix event stream subscription or reconnection logic. +- [ ] **If store not updating:** Fix Solid.js store update (ensure `produce` or proper setter is used). +- [ ] **If part lookup wrong:** Fix the part ID/callID matching between processor and TUI. + +### Milestone 4: Tests +- [ ] Add a session-level test to verify tool-result → part status `completed` transition. +- [ ] **If regression guard added:** Add a test that prevents `completed`/`error` → `running` status downgrade. +- [ ] Document TUI spinner verification as manual (no TUI harness today). + +### Milestone 5: Manual Validation +- [ ] Run a Bash command via the TUI and confirm the spinner stops. +- [ ] Verify at least one other tool (Write or Task) still updates correctly. +- [ ] **NEW:** Test with both short (<1s) and long (>5s) running commands. +- [ ] **NEW:** Test spinner behavior when command errors (non-zero exit). + +## Validation Criteria +### Automated +- [ ] `bun test` in `packages/opencode` passes. +- [ ] New tests cover status transitions and any regression guard (if added). + +### Manual +- [ ] Bash tool spinner disappears after command completion. +- [ ] Bash tool parts show `completed` or `error` statuses in transcript/history. +- [ ] No regressions in other tool spinners. + +### Suggested Commands +```bash +cd /home/shuv/repos/worktrees/shuvcode/shuvcode-dev/packages/opencode +bun test +``` + +## Current Findings + +Based on codebase review: + +1. **`ctx.metadata` guard exists but is not conclusive** + - Guard checks the in-memory toolcalls entry; late metadata can still race if the entry has not been cleared yet. +2. **Bash tool metadata calls are fire-and-forget** + - Streaming metadata updates (`bash.ts:201-217`) are not awaited and can arrive after completion. +3. **tool-result handler updates status when invoked** + - `processor.ts:171-188` sets status to `completed`; still verify it fires for Bash tool. + +## External References (Git URLs) +- https://github.com/sindresorhus/ora +- https://github.com/typesense/typesense/blob/e44a57004c981c8d7be7459d792a0fc971fdb05d/benchmark/src/services/typesense-process.ts +- https://github.com/vadimdemedes/pronto/blob/5e5ea6a8e38eec315542021010efd5d1efcb9e72/cli.js + +## Risks and Mitigations +| Risk | Impact | Mitigation | +| --- | --- | --- | +| Non-reactive `isRunning` is the root cause | High | Fix to reactive memo/inline check; re-test spinner behavior. | +| Metadata race causes status regression | Medium | Add regression guard and test; log ordering for confirmation. | +| Root cause is in Solid.js reactivity beyond Bash component | Medium | Use Solid.js DevTools or targeted logging to trace updates. | +| SSE disconnection causes missed updates | Medium | Check SSE reconnection logic; consider adding heartbeat verification. | +| Logging overwhelms output | Low | Gate logs behind debug flag or sample output. | +| Fix breaks other tool spinners | Medium | Add regression test for Write or Task tool and verify manually. | +| Investigation takes longer than fix | Low | Time-box investigation to 2 hours; document findings even if incomplete. | diff --git a/CONTEXT/PLAN-271-web-input-bar-bottom-padding-2026-01-06.md b/CONTEXT/PLAN-271-web-input-bar-bottom-padding-2026-01-06.md new file mode 100644 index 00000000000..a2705d3b662 --- /dev/null +++ b/CONTEXT/PLAN-271-web-input-bar-bottom-padding-2026-01-06.md @@ -0,0 +1,259 @@ +# Plan: Fix Web Input Bar Bottom Padding After Status Bar Removal + +**Issue:** [#271](https://github.com/Latitudes-Dev/shuvcode/issues/271) +**Created:** 2026-01-06 +**Type:** Bug Fix (CSS/Styling) +**Complexity:** Low +**Estimated Time:** 15-30 minutes + +--- + +## Problem Summary + +After removing the bottom status bar in commit `d60c9a9eb` (to adopt upstream changes where MCP/server info moved to the top header), the prompt input bar now sits flush against the bottom edge of the screen without adequate padding. This creates a cramped visual appearance and poor UX, especially on desktop. + +### Root Cause + +The `` component (32px height via `h-8` class) previously provided visual spacing at the bottom of the viewport. With its removal, no compensation was made for the lost vertical space. + +### Current State + +**File:** `packages/app/src/pages/session.tsx:984` + +```tsx +
(promptDock = el)} + class="absolute inset-x-0 bottom-0 pt-12 pb-4 md:pb-8 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" + style={{ "padding-bottom": "env(safe-area-inset-bottom, 0px)" }} +> +``` + +**Issues:** +1. `pb-4` (16px mobile) and `md:pb-8` (32px desktop) are insufficient now that the status bar is gone +2. The inline `style` with `env(safe-area-inset-bottom)` **overwrites** the Tailwind `pb-*` classes entirely on iOS devices +3. Desktop has no minimum padding guarantee + +--- + +## Technical Analysis + +### CSS Spacing Scale (Tailwind 4) + +| Class | Value | +|-------|-------| +| `pb-4` | 1rem (16px) | +| `pb-6` | 1.5rem (24px) | +| `pb-8` | 2rem (32px) | +| `pb-10` | 2.5rem (40px) | +| `pb-12` | 3rem (48px) | + +### Safe Area Inset Handling + +The current implementation has a flaw: using `style={{ "padding-bottom": "env(...)" }}` as an inline style **completely overrides** any Tailwind `pb-*` classes. This means: + +- On devices with no safe area (desktop, most Android), `env(safe-area-inset-bottom, 0px)` resolves to `0px`, leaving **no** bottom padding +- The Tailwind classes (`pb-4 md:pb-8`) are present but never applied due to inline style specificity + +### Best Practice Pattern + +From [Safari 15 Bottom Tab Bars article](https://samuelkraft.com/blog/safari-15-bottom-tab-bars-web) and MDN documentation, the recommended approach is to use `max()` to combine a minimum padding with the safe area inset: + +```css +padding-bottom: max(2rem, env(safe-area-inset-bottom, 0px)); +``` + +This ensures: +- Minimum 2rem (32px) padding on all devices +- Safe area inset is respected when it's larger than the minimum + +--- + +## Acceptance Criteria (from Issue) + +- [ ] Input bar has visible padding/margin from the bottom edge on desktop (minimum ~16-24px) +- [ ] Mobile safe area insets are still respected via `env(safe-area-inset-bottom)` +- [ ] The gradient background still fades correctly above the input +- [ ] Visual consistency with the previous appearance (when status bar existed) + +--- + +## Implementation Plan + +### Task 1: Update Prompt Dock Container Styling + +**File:** `packages/app/src/pages/session.tsx` +**Line:** ~984 + +#### Approach A: Use CSS `max()` Function (Recommended) + +Replace the separate `class` and `style` attributes with a combined approach using `max()`: + +```diff +
(promptDock = el)} +- class="absolute inset-x-0 bottom-0 pt-12 pb-4 md:pb-8 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" +- style={{ "padding-bottom": "env(safe-area-inset-bottom, 0px)" }} ++ class="absolute inset-x-0 bottom-0 pt-12 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" ++ style={{ "padding-bottom": "max(1.5rem, env(safe-area-inset-bottom, 0px))" }} +> +``` + +**Rationale:** +- `max(1.5rem, env(...))` ensures minimum 24px padding while respecting larger safe areas +- Removes redundant `pb-4 md:pb-8` classes that were being overridden anyway +- Single source of truth for bottom padding + +#### Approach B: Increase Tailwind Classes + Fix Style Override + +If we want to keep the Tailwind classes for responsive behavior: + +```diff +
(promptDock = el)} +- class="absolute inset-x-0 bottom-0 pt-12 pb-4 md:pb-8 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" +- style={{ "padding-bottom": "env(safe-area-inset-bottom, 0px)" }} ++ class="absolute inset-x-0 bottom-0 pt-12 pb-6 md:pb-10 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" ++ style={{ "padding-bottom": "max(var(--tw-pb), env(safe-area-inset-bottom, 0px))" }} +> +``` + +**Note:** Tailwind 4 doesn't expose `--tw-pb` directly, so Approach A is cleaner. + +#### Approach C: Use CSS Variables (as done in askquestion-wizard.tsx) + +Following the pattern in `packages/app/src/components/askquestion-wizard.tsx:336`: + +```tsx +style={{ "padding-bottom": "calc(1.5rem + var(--safe-area-inset-bottom))" }} +``` + +Where `--safe-area-inset-bottom` is defined in `packages/app/src/index.css`: + +```css +:root { + --safe-area-inset-bottom: env(safe-area-inset-bottom, 0px); +} +``` + +**Note:** This adds to the safe area rather than taking the max, which could result in excessive padding on iOS devices. + +### Recommended Solution + +**Use Approach A** with `max()` function: + +- [ ] **1.1** Edit `packages/app/src/pages/session.tsx:984` +- [ ] **1.2** Remove `pb-4 md:pb-8` from class string +- [ ] **1.3** Update style to use `max(1.5rem, env(safe-area-inset-bottom, 0px))` + +If different padding is desired for mobile vs desktop, consider: +```tsx +style={{ + "padding-bottom": window.innerWidth >= 768 + ? "max(2.5rem, env(safe-area-inset-bottom, 0px))" // Desktop: 40px min + : "max(1.5rem, env(safe-area-inset-bottom, 0px))" // Mobile: 24px min +}} +``` + +However, for simplicity and SSR compatibility, a single `max()` value is preferred. + +--- + +### Task 2: Verify Gradient Background + +- [ ] **2.1** Confirm gradient (`bg-gradient-to-t from-background-stronger via-background-stronger to-transparent`) still displays correctly with increased padding +- [ ] **2.2** Test that the gradient fades properly above the input area + +The gradient is applied to the container, not the padding, so it should adapt automatically. + +--- + +### Task 3: Test Across Viewports + +- [ ] **3.1** Test on desktop browser (Chrome/Firefox/Safari) at various widths +- [ ] **3.2** Test on mobile simulator or device (iOS Safari, Chrome Android) +- [ ] **3.3** Test in PWA mode on iOS (Dynamic Island consideration) +- [ ] **3.4** Verify safe area insets work on devices with home indicators + +--- + +### Task 4: Visual QA + +- [ ] **4.1** Compare before/after screenshots +- [ ] **4.2** Verify input bar no longer appears flush against bottom edge +- [ ] **4.3** Confirm minimum 24px visible padding on desktop +- [ ] **4.4** Ensure no excessive whitespace (keep it balanced) + +--- + +## Code References + +### Internal Files + +| File | Purpose | +|------|---------| +| `packages/app/src/pages/session.tsx:984` | Prompt dock container (target of fix) | +| `packages/app/src/pages/session.tsx:985` | Current inline style with `env()` | +| `packages/app/src/index.css:6-11` | CSS variable definitions for safe area insets | +| `packages/app/src/components/status-bar.tsx:49` | Removed StatusBar component (reference for original spacing: `h-8` = 32px) | +| `packages/app/src/components/askquestion-wizard.tsx:336` | Similar safe area handling pattern | + +### Related Commits + +| Commit | Description | +|--------|-------------| +| `d60c9a9eb` | Removed StatusBar, causing this issue | +| `90d5fc834` | Adopted upstream header pattern (context) | + +### External References + +| Resource | URL | +|----------|-----| +| Safari 15 Bottom Tab Bars (safe area patterns) | https://samuelkraft.com/blog/safari-15-bottom-tab-bars-web | +| MDN env() function | https://developer.mozilla.org/en-US/docs/Web/CSS/env | +| CSS max() function | https://developer.mozilla.org/en-US/docs/Web/CSS/max | + +--- + +## Testing Commands + +```bash +# Start development server +cd packages/app && bun dev + +# Open in browser at http://localhost:3001 +# Test at various viewport sizes + +# For iOS testing, use Safari's Responsive Design Mode +# or connect a real device via Safari Web Inspector +``` + +--- + +## Rollback Plan + +If the fix causes issues: + +1. Revert the single line change in `session.tsx:984-985` +2. Restore original classes: `pb-4 md:pb-8` +3. Restore original style: `{ "padding-bottom": "env(safe-area-inset-bottom, 0px)" }` + +--- + +## Definition of Done + +- [ ] Input bar has minimum ~24px padding from bottom edge on desktop +- [ ] Mobile safe area insets (iPhone notch/home indicator) are respected +- [ ] Gradient background fades correctly +- [ ] Visual regression testing passed +- [ ] No TypeScript errors +- [ ] Works in standard browser and PWA mode +- [ ] PR created and reviewed + +--- + +## Notes + +- This is a low-risk, single-file CSS change +- No tests required (visual/CSS change) +- Should be a quick fix once the approach is decided +- The `max()` CSS function has excellent browser support (96%+ globally) diff --git a/CONTEXT/PLAN-tauri-mobile-support-2026-01-06.md b/CONTEXT/PLAN-tauri-mobile-support-2026-01-06.md new file mode 100644 index 00000000000..f37b4403fb8 --- /dev/null +++ b/CONTEXT/PLAN-tauri-mobile-support-2026-01-06.md @@ -0,0 +1,912 @@ +# Tauri Mobile Support Implementation Plan + +**Date:** 2026-01-06 +**Author:** Shuvcode Fork Team +**Status:** Draft +**Target:** Android & iOS native apps via Tauri v2 + +## Executive Summary + +This plan outlines the implementation of native mobile app support for the shuvcode fork using Tauri v2's mobile capabilities. The fork already has excellent PWA support with mobile-optimized components. This plan builds on that foundation to create native Android and iOS apps that provide better platform integration, offline support, and App Store/Play Store distribution. + +## Current State Analysis + +### Existing Mobile Infrastructure (PWA) + +The shuvcode fork already has significant mobile-ready infrastructure: + +| Component | Location | Purpose | +|-----------|----------|---------| +| `MobileTerminalInput` | `packages/app/src/components/mobile-terminal-input.tsx` | Hidden input bridge for mobile keyboard to terminal WebSocket | +| `PullToRefresh` | `packages/app/src/components/pull-to-refresh.tsx` | Touch gesture detection for iOS-style pull-to-refresh | +| `useKeyboardVisibility` | `packages/app/src/hooks/use-keyboard-visibility.tsx` | Visual viewport API hook for mobile keyboard detection | +| Mobile sidebar | `packages/app/src/context/layout.tsx` | `mobileSidebar` state, drawer-style navigation | +| Mobile tabs | `packages/app/src/pages/session.tsx` | Session/Review tab switcher for mobile | +| Safe area insets | `packages/app/src/index.css` | CSS variables for notch/dynamic island handling | +| PWA manifest | `packages/app/public/site.webmanifest` | Standalone display, portrait orientation | +| Service worker | `packages/app/vite.config.ts` | VitePWA with offline caching | + +### Existing Desktop Tauri Infrastructure + +The desktop Tauri app provides a solid foundation: + +| Component | Location | Purpose | +|-----------|----------|---------| +| `tauri.conf.json` | `packages/desktop/src-tauri/tauri.conf.json` | App configuration, bundle settings | +| `Cargo.toml` | `packages/desktop/src-tauri/Cargo.toml` | Rust dependencies, Tauri plugins | +| `lib.rs` | `packages/desktop/src-tauri/src/lib.rs` | Main app logic, sidecar management | +| `cli.rs` | `packages/desktop/src-tauri/src/cli.rs` | CLI installation, path resolution | +| `window_customizer.rs` | `packages/desktop/src-tauri/src/window_customizer.rs` | Pinch zoom disable (Linux only) | +| Mobile icons | `packages/desktop/src-tauri/icons/prod/android/` | Pre-generated Android mipmap icons | +| iOS icons | `packages/desktop/src-tauri/icons/prod/ios/` | Pre-generated iOS AppIcon assets | +| Platform context | `packages/app/src/context/platform.tsx` | Platform abstraction layer | +| Desktop entry | `packages/desktop/src/index.tsx` | Tauri platform implementation | + +### Key Observation: Mobile Entry Point Exists + +The codebase already includes the mobile entry point attribute: +```rust +// packages/desktop/src-tauri/src/lib.rs:193 +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { +``` + +This indicates the Rust side is partially prepared for mobile builds. + +## Technical Challenges + +### 1. Sidecar Binary Architecture + +**Current Desktop Approach:** +- Desktop app spawns a sidecar binary (`shuvcode-cli`) that runs the server +- Server listens on localhost and WebView connects to it +- Sidecar handles all agent functionality, LSP, MCP, file operations + +**Mobile Challenge:** +- iOS does not allow spawning background processes/sidecars +- Android has similar restrictions in recent versions +- Mobile apps run in sandboxed environments + +**Solution Options:** + +| Option | Pros | Cons | Recommendation | +|--------|------|------|----------------| +| **A. Remote Server** | Simple, works today | Requires network, no offline | For MVP/testing | +| **B. Embedded Rust Server** | True native, offline capable | Complex FFI, larger binary | Long-term goal | +| **C. WebAssembly Runtime** | Cross-platform, sandboxed | Performance limitations | Experimental | + +### 2. Terminal Emulation + +**Current State:** +- Uses `ghostty-web` WASM module for terminal rendering +- WebSocket connection to PTY server endpoint +- MobileTerminalInput bridges native keyboard + +**Mobile Challenge:** +- PTY server runs in sidecar (not available on mobile) +- Need alternative for shell access + +**Solution:** +- Phase 1: Connect to remote shuvcode server (existing PWA behavior) +- Phase 2: Explore terminal.js alternatives or WebSocket proxy + +### 3. File System Access + +**Current Desktop:** +- Full filesystem access via Tauri's fs plugin +- Native file/directory pickers + +**Mobile Challenge:** +- iOS: Sandboxed app container + Files app integration +- Android: Scoped storage since Android 11 + +**Solution:** +- Use Tauri's mobile-compatible plugins +- Integrate with system file providers +- In the MVP, rely on the remote server filesystem (no device-local project storage) +- Consider workspace sync via Git or cloud storage + +### 4. Server URL Resolution & Persistence + +**Current State:** +- `defaultServerUrl` is computed synchronously in `packages/app/src/app.tsx` +- Server selection and persistence live in `ServerProvider` (`packages/app/src/context/server.tsx`) +- `DialogSelectServer` already supports add/switch + health checks + +**Mobile Challenge:** +- Mobile needs a remote server URL injected before `App` renders +- Adding a separate mobile server dialog risks divergence + +**Solution:** +- Inject `window.__SHUVCODE__.serverUrl` in the mobile entry before render +- Update `defaultServerUrl` to check this value first +- Reuse `DialogSelectServer` for all server changes + +## Implementation Plan + +### Phase 1: Project Initialization & Configuration + +#### 1.1 Initialize Tauri Mobile Targets + +- [ ] Run `bun tauri android init` in `packages/desktop` +- [ ] Run `bun tauri ios init` in `packages/desktop` +- [ ] Verify generated files: + - `src-tauri/gen/android/` - Android Studio project + - `src-tauri/gen/apple/` - Xcode project + +**Files Created:** +``` +packages/desktop/src-tauri/ + gen/ + android/ + app/ + build.gradle.kts + src/main/ + AndroidManifest.xml + java/ai/shuv/desktop/ + MainActivity.kt + res/ + build.gradle.kts + settings.gradle.kts + apple/ + Shuvcode.xcodeproj/ + Shuvcode/ + Info.plist + Assets.xcassets/ +``` + +#### 1.2 Configure Mobile Identifiers + +- [ ] Update `packages/desktop/src-tauri/tauri.conf.json` with shared mobile identifiers and defaults. +- [ ] Add mobile overrides in `packages/desktop/src-tauri/tauri.android.conf.json` and `packages/desktop/src-tauri/tauri.ios.conf.json` (do not place these at repo root). +- [ ] Update `packages/desktop/src-tauri/tauri.prod.conf.json` so production identifiers and plugin config are correct for mobile (e.g., disable updater on mobile builds). + +```json +{ + "identifier": "ai.shuv.shuvcode", + "bundle": { + "iOS": { + "developmentTeam": "YOUR_TEAM_ID", + "minimumSystemVersion": "13.0" + }, + "android": { + "minSdkVersion": 24 + } + } +} +``` + +**Reference Files:** +- `packages/desktop/src-tauri/tauri.conf.json:1-43` +- `packages/desktop/src-tauri/tauri.prod.conf.json:1-33` + +#### 1.3 Configure App Icons + +- [ ] Verify existing icons in `packages/desktop/src-tauri/icons/prod/android/` +- [ ] Verify existing icons in `packages/desktop/src-tauri/icons/prod/ios/` +- [ ] Add dev variant icons for debug builds +- [ ] Run `bun tauri icon` if regeneration needed + +**Current Icon Structure:** +``` +packages/desktop/src-tauri/icons/ + prod/ + android/ + mipmap-hdpi/ + mipmap-mdpi/ + mipmap-xhdpi/ + mipmap-xxhdpi/ + mipmap-xxxhdpi/ + mipmap-anydpi-v26/ + values/ + ios/ + AppIcon-20x20@*.png + AppIcon-29x29@*.png + AppIcon-40x40@*.png + AppIcon-60x60@*.png + AppIcon-76x76@*.png + AppIcon-83.5x83.5@2x.png + AppIcon-512@2x.png +``` + +### Phase 2: Rust Mobile Adaptation + +#### 2.1 Conditional Compilation for Mobile + +- [ ] Split `run()` into `run_desktop()` and `run_mobile()` and gate all desktop-only modules/commands (sidecar, window customizer, clipboard, updater, shell/process) with `cfg(not(mobile))` so mobile builds compile cleanly. + +```rust +// packages/desktop/src-tauri/src/lib.rs + +#[cfg(not(mobile))] +mod cli; +#[cfg(not(mobile))] +mod window_customizer; + +#[cfg(not(mobile))] +use cli::{get_sidecar_path, install_cli, sync_cli}; + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + #[cfg(mobile)] + { + // Mobile-specific initialization + run_mobile(); + } + + #[cfg(not(mobile))] + { + // Existing desktop code + run_desktop(); + } +} + +#[cfg(mobile)] +fn run_mobile() { + tauri::Builder::default() + .plugin(tauri_plugin_os::init()) + .plugin(tauri_plugin_store::Builder::new().build()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_http::init()) + .plugin(tauri_plugin_notification::init()) + // Note: shell plugin limited on mobile + // Note: window-state not needed on mobile + // Note: updater works differently on mobile (app stores) + .invoke_handler(tauri::generate_handler![ + // Mobile-safe commands only + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} +``` + +**Reference Files:** +- `packages/desktop/src-tauri/src/lib.rs:193-330` + +#### 2.2 Update Cargo.toml for Mobile + +- [ ] Add mobile-specific dependencies: + +```toml +# packages/desktop/src-tauri/Cargo.toml + +[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] +# Mobile-specific deps +log = "0.4" + +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +# Desktop-only deps +gtk = "0.18.2" +webkit2gtk = "=2.0.1" +listeners = "0.3" + +[dependencies] +# Common deps - verify mobile compatibility +tauri = { version = "2", features = ["macos-private-api", "devtools"] } +# Note: Remove features not available on mobile +``` + +- [ ] Remove/conditionally compile desktop-only plugins: + - `tauri-plugin-updater` - App store handles updates on mobile + - `tauri-plugin-window-state` - Not applicable to mobile + - `tauri-plugin-clipboard-manager` - Requires mobile permissions +- [ ] Update `packages/desktop/src-tauri/tauri.prod.conf.json` to ensure updater config remains desktop-only and does not affect mobile builds. + +**Reference Files:** +- `packages/desktop/src-tauri/Cargo.toml:1-43` +- `packages/desktop/src-tauri/tauri.prod.conf.json:1-33` + +#### 2.3 Add Mobile Commands + +- [ ] Create mobile-specific Tauri commands: + +```rust +// packages/desktop/src-tauri/src/mobile.rs (new file) + +#[cfg(mobile)] +use tauri::command; + +#[cfg(mobile)] +#[command] +pub fn get_server_url() -> String { + // Return configured server URL for remote connection + std::env::var("SHUVCODE_SERVER_URL") + .unwrap_or_else(|_| "https://your-server.shuv.ai".to_string()) +} + +#[cfg(mobile)] +#[command] +pub fn is_mobile() -> bool { + true +} +``` + +### Phase 3: Mobile Capabilities & Permissions + +#### 3.1 Create Mobile Capabilities File + +- [ ] Create `packages/desktop/src-tauri/capabilities/mobile.json`: + +```json +{ + "$schema": "../gen/schemas/mobile-schema.json", + "identifier": "mobile", + "description": "Capability for mobile platforms", + "platforms": ["android", "iOS"], + "permissions": [ + "core:default", + "opener:default", + "dialog:default", + "store:default", + "os:default", + "notification:default", + { + "identifier": "http:default", + "allow": [ + { "url": "http://*" }, + { "url": "https://*" } + ] + } + ] +} +``` + +**Reference Files:** +- `packages/desktop/src-tauri/capabilities/default.json:1-29` + +#### 3.2 Configure Android Permissions + +- [ ] Update `AndroidManifest.xml` (generated, may need customization): + +```xml + + + + + + + + + + +``` + +#### 3.3 Configure iOS Permissions + +- [ ] Update `Info.plist` (generated, may need customization): + +```xml + +UIFileSharingEnabled + +LSSupportsOpeningDocumentsInPlace + + + +NSUserNotificationUsageDescription +Notifications for agent completions and errors +``` + +### Phase 4: Frontend Mobile Platform Implementation + +#### 4.1 Create Mobile Platform Context + +- [ ] Create `packages/desktop/src/mobile.tsx`: + +```tsx +// Mobile platform implementation +import { Platform, PlatformProvider } from "@opencode-ai/app" +import { App } from "@opencode-ai/app" +import { AsyncStorage } from "@solid-primitives/storage" +import { Store } from "@tauri-apps/plugin-store" +import { fetch as tauriFetch } from "@tauri-apps/plugin-http" +import { open as shellOpen } from "@tauri-apps/plugin-opener" +import pkg from "../package.json" + +const mobilePlatform: Platform = { + platform: "mobile" as const, // New platform type + version: pkg.version, + + openLink(url: string) { + void shellOpen(url).catch(() => undefined) + }, + + storage: (name = "default.dat") => { + // Reuse the exact AsyncStorage implementation from packages/desktop/src/index.tsx + // so persisted stores (server.v4, notification.v1, etc.) behave identically. + const api: AsyncStorage = { + // ... (copy implementation, no stub) + } + return api + }, + + restart: async () => { + // Mobile apps don't restart - reload webview + window.location.reload() + }, + + notify: async (title, description, href) => { + // Use Tauri notification plugin + // Implementation depends on plugin availability + }, + + // Mobile-specific: No directory picker (use server-side browse) + // Mobile-specific: No file picker (limited) + // Mobile-specific: No updater (app store) + + fetch: tauriFetch as typeof fetch, +} + +export function MobileApp() { + return ( + + + + ) +} +``` + +**Reference Files:** +- `packages/desktop/src/index.tsx:1-207` +- `packages/app/src/context/platform.tsx:1-58` + +#### 4.2 Update Platform Type and Branches + +- [ ] Update `packages/app/src/context/platform.tsx` to include `"mobile"` in the platform union. +- [ ] Extend the `Window.__SHUVCODE__` type in `packages/app/src/app.tsx` to include `serverUrl?: string` for mobile server injection. +- [ ] Audit platform branches (for example, `platform.platform === "desktop"` in `packages/app/src/pages/session.tsx`) and define mobile behavior. Default to web behavior unless a mobile-specific override is required. +- [ ] Keep directory/file picker APIs undefined on mobile so browse buttons are hidden in `DialogCreateProject`. + +```tsx +export type Platform = { + /** Platform discriminator */ + platform: "web" | "desktop" | "mobile" + // ... rest unchanged +} + +declare global { + interface Window { + __SHUVCODE__?: { updaterEnabled?: boolean; port?: number; serverUrl?: string } + } +} +``` + +#### 4.3 Create Mobile Entry Point + +- [ ] Create `packages/desktop/src/mobile-entry.tsx` that resolves the mobile server URL via `invoke("get_server_url")`, injects it into `window.__SHUVCODE__`, then renders `MobileApp`. +- [ ] Ensure this runs before `App` renders so `defaultServerUrl` can read `window.__SHUVCODE__.serverUrl`. +- [ ] If top-level await is not supported by the current build target, wrap the initialization in an async IIFE before calling `render()`. + +```tsx +// Mobile-specific entry point +import { render } from "solid-js/web" +import { invoke } from "@tauri-apps/api/core" +import { MobileApp } from "./mobile" + +const root = document.getElementById("root") +if (!(root instanceof HTMLElement)) { + throw new Error("Root element not found") +} + +const serverUrl = await invoke("get_server_url").catch(() => "") +if (serverUrl) { + window.__SHUVCODE__ = { ...(window.__SHUVCODE__ ?? {}), serverUrl } +} + +render(() => , root) +``` + +#### 4.4 Configure Vite/HTML for Mobile + +- [ ] Validate how `@opencode-ai/app/vite` handles entrypoints; prefer reusing `packages/desktop/index.html` to preserve the theme preload script and current meta tags. +- [ ] If a separate HTML entry is required, duplicate `packages/desktop/index.html` to `packages/desktop/mobile.html` and keep the `oc-theme-preload-script` and existing meta tags. Only then update `packages/desktop/vite.config.ts` to point to the alternate HTML. + +### Phase 5: Server Connection Strategy + +#### 5.1 Remote Server Configuration (reuse existing server flow) + +For the initial mobile release, the app will act as a remote-server client and reuse the existing server selection/persistence system: + +- [ ] Inject the mobile default server URL via `window.__SHUVCODE__.serverUrl` (set in the mobile entry) and update `defaultServerUrl` in `packages/app/src/app.tsx` to check this before localhost/origin. +- [ ] Reuse `ServerProvider` persistence (`server.v4`) and `DialogSelectServer` for adding/switching servers (no mobile-only server dialog). +- [ ] Confirm health checks and requests use `platform.fetch` so Tauri's HTTP plugin is respected on mobile. + +```tsx +// packages/app/src/app.tsx +const defaultServerUrl = iife(() => { + if (window.__SHUVCODE__?.serverUrl) return window.__SHUVCODE__.serverUrl + // existing resolution logic... +}) +``` + +#### 5.2 Mobile UX for Remote Filesystem + +- [ ] Update copy in `DialogCreateProject` to clarify that browsing/creating projects happens on the connected server filesystem when running on mobile. +- [ ] Keep `platform.openDirectoryPickerDialog` undefined on mobile so the Browse buttons remain hidden (already gated by `Show when={platform.openDirectoryPickerDialog}`). +- [ ] Confirm `StatusBar` is visible on mobile (PWA hiding logic should not apply) so `DialogSelectServer` remains reachable. +- [ ] Document the authentication flow for remote servers (OAuth/deep link if required). + +### Phase 6: Build & Test Infrastructure + +#### 6.1 Android Development Setup + +- [ ] Document Android SDK requirements: + - Android Studio + - Android SDK (API 24+) + - NDK (for Rust compilation) + - Java 17+ + +- [ ] Add npm scripts to `packages/desktop/package.json`: + +```json +{ + "scripts": { + "android:init": "tauri android init", + "android:dev": "tauri android dev", + "android:build": "tauri android build", + "android:build:apk": "tauri android build --apk", + "android:build:aab": "tauri android build --aab" + } +} +``` + +#### 6.2 iOS Development Setup + +- [ ] Document iOS development requirements: + - macOS + - Xcode 14+ + - Apple Developer account + - iOS Simulator or device + +- [ ] Add npm scripts: + +```json +{ + "scripts": { + "ios:init": "tauri ios init", + "ios:dev": "tauri ios dev", + "ios:build": "tauri ios build" + } +} +``` + +#### 6.3 Rust Target Installation + +- [ ] Document required Rust targets: + +```bash +# Android targets +rustup target add aarch64-linux-android +rustup target add armv7-linux-androideabi +rustup target add i686-linux-android +rustup target add x86_64-linux-android + +# iOS targets +rustup target add aarch64-apple-ios +rustup target add x86_64-apple-ios +rustup target add aarch64-apple-ios-sim +``` + +### Phase 7: CI/CD Integration + +#### 7.1 Android Build Workflow + +- [ ] Create `.github/workflows/mobile-android.yml`: + +```yaml +name: Android Build + +on: + push: + tags: + - 'android-v*' + workflow_dispatch: + +jobs: + build-android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Setup Rust + uses: dtolnay/rust-action@stable + with: + targets: aarch64-linux-android,armv7-linux-androideabi + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + + - name: Install dependencies + run: bun install + working-directory: packages/desktop + + - name: Build Android + run: bun tauri android build --apk + working-directory: packages/desktop + + - name: Upload APK + uses: actions/upload-artifact@v4 + with: + name: android-apk + path: packages/desktop/src-tauri/gen/android/app/build/outputs/apk/ +``` + +#### 7.2 iOS Build Workflow + +- [ ] Create `.github/workflows/mobile-ios.yml`: + +```yaml +name: iOS Build + +on: + push: + tags: + - 'ios-v*' + workflow_dispatch: + +jobs: + build-ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Setup Rust + uses: dtolnay/rust-action@stable + with: + targets: aarch64-apple-ios,aarch64-apple-ios-sim + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + + - name: Install dependencies + run: bun install + working-directory: packages/desktop + + - name: Build iOS + run: bun tauri ios build + working-directory: packages/desktop + env: + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} +``` + +### Phase 8: Testing Strategy + +#### 8.1 Automated Tests + +- [ ] Add tests (or a minimal harness) for `defaultServerUrl` resolution and server persistence behavior. If no frontend test harness exists, document why and rely on manual validation. + +#### 8.2 Manual Testing Checklist + +- [ ] **App Launch** + - [ ] App launches without crash + - [ ] Server connection established + - [ ] Server selection dialog opens and persists choice + - [ ] Login/authentication works + +- [ ] **Session Management** + - [ ] Create new session + - [ ] View session list + - [ ] Switch between sessions + - [ ] Delete session + +- [ ] **Chat Interface** + - [ ] Send message + - [ ] View AI response + - [ ] Code blocks render correctly + - [ ] Markdown formatting works + +- [ ] **Mobile UI** + - [ ] Mobile sidebar works (drawer) + - [ ] Pull-to-refresh works + - [ ] Keyboard visibility handled + - [ ] Safe area insets correct + - [ ] Orientation changes handled + +- [ ] **Offline Behavior** + - [ ] Graceful error on no connection + - [ ] Reconnection when network restored + - [ ] No offline usage in MVP unless embedded server is implemented + +#### 8.3 Platform-Specific Testing + +**Android:** +- [ ] Back button behavior +- [ ] Recent apps thumbnail +- [ ] Local notifications (non-push) +- [ ] Deep linking + +**iOS:** +- [ ] Home indicator handling +- [ ] Dynamic Island compatibility +- [ ] Face ID/Touch ID (if applicable) +- [ ] Local notifications (non-push) + +### Phase 9: App Store Preparation + +#### 9.1 Android Play Store + +- [ ] Create signing keystore +- [ ] Configure `build.gradle.kts` for release signing +- [ ] Prepare Play Store listing: + - App name: "shuvcode" + - Short description + - Full description + - Screenshots (phone, tablet) + - Feature graphic + - Privacy policy URL + +#### 9.2 iOS App Store + +- [ ] Apple Developer account setup +- [ ] App Store Connect configuration +- [ ] Prepare App Store listing: + - App name + - Description + - Keywords + - Screenshots (all required sizes) + - Privacy policy URL + - App Privacy labels + +## External References + +### Tauri Mobile Documentation + +- https://v2.tauri.app/start/prerequisites/ - Setup requirements +- https://v2.tauri.app/develop/configuration-files/ - Config structure +- https://v2.tauri.app/reference/cli/ - CLI commands (`tauri android`, `tauri ios`) +- https://v2.tauri.app/security/capabilities/ - Mobile capabilities +- https://v2.tauri.app/security/permissions/ - Permission system +- https://v2.tauri.app/develop/plugins/develop-mobile/ - Mobile plugin development +- https://v2.tauri.app/distribute/sign/android/ - Android signing + +### Example Tauri Mobile Projects + +- https://github.com/tauri-apps/cargo-mobile2 - cargo-mobile2 tool +- https://github.com/jbilcke/latent-browser - Example mobile Tauri app +- https://github.com/readest/readest - Production Tauri mobile app +- https://github.com/EasyTier/EasyTier - Cross-platform including mobile + +### Tauri Plugins + +- https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins - Official plugins +- Notable mobile-compatible plugins: + - `tauri-plugin-http` - Network requests + - `tauri-plugin-notification` - Local/system notifications (non-push) + - `tauri-plugin-store` - Key-value storage + - `tauri-plugin-os` - OS information + - `tauri-plugin-dialog` - File dialogs (limited on mobile) + +## Internal File References + +### Core Files to Modify + +| File | Purpose | Changes Required | +|------|---------|------------------| +| `packages/desktop/src-tauri/src/lib.rs` | Tauri app entry | Split desktop vs mobile boot; gate sidecar/plugins | +| `packages/desktop/src-tauri/Cargo.toml` | Rust deps | Target-specific deps for mobile vs desktop | +| `packages/desktop/src-tauri/tauri.conf.json` | App config | Shared identifiers/defaults | +| `packages/desktop/src-tauri/tauri.prod.conf.json` | Prod config | Desktop-only updater config; avoid mobile | +| `packages/desktop/src-tauri/capabilities/default.json` | Desktop permissions | Keep desktop capabilities separate | +| `packages/desktop/vite.config.ts` | Vite config | Optional entrypoint adjustments (validate plugin) | +| `packages/desktop/index.html` | HTML template | Preserve theme preload if duplicated for mobile | +| `packages/desktop/package.json` | NPM scripts | Mobile build commands | +| `packages/app/src/app.tsx` | App bootstrap | `defaultServerUrl` mobile hook + `__SHUVCODE__` typing | +| `packages/app/src/pages/session.tsx` | Platform layout | Confirm mobile vs desktop branching | +| `packages/app/src/context/server.tsx` | Server state | Reuse persisted server list on mobile | +| `packages/app/src/components/dialog-select-server.tsx` | Server UI | Reuse for mobile server selection | +| `packages/app/src/context/platform.tsx` | Platform types | Add "mobile" type | + +### Files to Create + +| File | Purpose | +|------|---------| +| `packages/desktop/src/mobile.tsx` | Mobile platform implementation | +| `packages/desktop/src/mobile-entry.tsx` | Mobile entry point | +| `packages/desktop/mobile.html` | Mobile HTML template (optional) | +| `packages/desktop/src-tauri/capabilities/mobile.json` | Mobile capabilities | +| `packages/desktop/src-tauri/src/mobile.rs` | Mobile Rust commands | +| `packages/desktop/src-tauri/tauri.android.conf.json` | Android config overrides | +| `packages/desktop/src-tauri/tauri.ios.conf.json` | iOS config overrides | +| `.github/workflows/mobile-android.yml` | Android CI | +| `.github/workflows/mobile-ios.yml` | iOS CI | + +### Existing PWA Mobile Components (Reuse) + +| File | What to Reuse | +|------|---------------| +| `packages/app/src/components/mobile-terminal-input.tsx` | Terminal keyboard bridge | +| `packages/app/src/components/pull-to-refresh.tsx` | Pull gesture handler | +| `packages/app/src/hooks/use-keyboard-visibility.tsx` | Keyboard detection | +| `packages/app/src/context/layout.tsx` | mobileSidebar state | +| `packages/app/src/pages/session.tsx` | Mobile tabs, mobileReview | +| `packages/app/src/index.css` | Safe area CSS variables | + +## Risk Assessment + +| Risk | Impact | Likelihood | Mitigation | +|------|--------|------------|------------| +| Sidecar not possible on mobile | High | Certain | Remote server architecture | +| Remote server UX mismatch with local filesystem | Medium | Medium | Update UI copy/flows; hide local browse controls on mobile | +| Server URL resolution/persistence regressions | Medium | Medium | Integrate with `ServerProvider` + add tests for `defaultServerUrl` | +| Performance issues | Medium | Medium | Profile and optimize, reduce bundle | +| App Store rejection | High | Low | Follow guidelines, thorough testing | +| Terminal depends on remote PTY | Medium | Medium | Require healthy remote server; document no offline support | +| iOS signing complexity | Low | Medium | Document process, use CI | + +## Success Criteria + +1. **MVP (Phase 1-5):** + - [ ] App builds for Android and iOS + - [ ] Connects to remote shuvcode server and passes health checks + - [ ] Server selection persists via `ServerProvider` (`server.v4`) + - [ ] Basic chat functionality works + - [ ] Mobile UI renders correctly, with remote filesystem copy in project flows + - [ ] Offline mode shows clear error messaging (no offline support in MVP) + +2. **Beta (Phase 6-7):** + - [ ] CI builds working + - [ ] Internal testing complete + - [ ] Performance acceptable + +3. **Release (Phase 8-9):** + - [ ] All manual tests pass + - [ ] App Store listings prepared + - [ ] First public release + +## Timeline Estimate + +| Phase | Duration | Dependencies | +|-------|----------|--------------| +| Phase 1: Init | 1-2 days | None | +| Phase 2: Rust | 2-3 days | Phase 1 | +| Phase 3: Capabilities | 1 day | Phase 2 | +| Phase 4: Frontend | 2-3 days | Phase 2 | +| Phase 5: Server | 1-2 days | Phase 4 | +| Phase 6: Build | 2-3 days | Phase 5 | +| Phase 7: CI | 2-3 days | Phase 6 | +| Phase 8: Testing | 3-5 days | Phase 7 | +| Phase 9: Release | 2-5 days | Phase 8 | + +**Total Estimate:** 3-4 weeks for MVP, 5-6 weeks for full release + +## Future Enhancements + +After initial release, consider: + +1. **Embedded Server (Long-term)** + - Compile opencode core to static lib + - FFI bridge to Rust + - True offline capability + +2. **Git Integration** + - Clone repos to device + - Commit and push support + - SSH key management + +3. **Voice Input** + - Speech-to-text for prompts + - Hands-free operation + +4. **Widgets** + - iOS widgets for quick access + - Android app shortcuts + +5. **Watch Companion** + - Apple Watch notifications + - Wear OS integration diff --git a/LOCAL_TAURI_PUBLISH.md b/LOCAL_TAURI_PUBLISH.md new file mode 100644 index 00000000000..b182fe4d61a --- /dev/null +++ b/LOCAL_TAURI_PUBLISH.md @@ -0,0 +1,74 @@ +# Local Tauri Publish (Shuvcode) + +This guide is local-only: build, sign, and publish the desktop app without GitHub Actions. + +## 1) Prerequisites + +- Bun and Rust installed (host triple in `rustc -vV`). +- Tauri CLI available via `bun run tauri` in `packages/desktop`. +- Linux-only bundling dependencies for AppImage: + - Install `fuse2` (or set `APPIMAGE_EXTRACT_AND_RUN=1` to avoid FUSE). + - Ensure `glibc`, `gtk3`, `webkit2gtk`, and related system libs are installed. + +## 2) Branding + updater config you must own + +- Set the updater public key to your Shuvcode key in `packages/desktop/src-tauri/tauri.prod.conf.json`. +- Confirm updater endpoint uses your repo: `https://github.com/Latitudes-Dev/shuvcode/releases/latest/download/latest.json`. +- Ensure bundle identifiers are correct: + - Dev: `dev.shuvcode.desktop.dev` + - Prod: `dev.shuvcode.desktop` + +## 3) Generate signing keys (one-time) + +Run locally: + +```bash +bun run --cwd packages/desktop tauri signer generate -w ./shuvcode-private.key +``` + +- The command prints a public key; copy that into `plugins.updater.pubkey` in `packages/desktop/src-tauri/tauri.prod.conf.json`. +- Store the private key securely. If you set a password, also store it. + +## 4) Local build workflow (per release) + +```bash +export RUST_TARGET=x86_64-unknown-linux-gnu +bun run --cwd packages/desktop predev +bun run --cwd packages/desktop build +TAURI_SIGNING_PRIVATE_KEY="$(cat ./shuvcode-private.key)" \ +TAURI_SIGNING_PRIVATE_KEY_PASSWORD="" \ +bun run --cwd packages/desktop tauri build +``` + +Outputs appear in: + +- Bundles: `packages/desktop/src-tauri/target/release/bundle/` +- App binary: `packages/desktop/src-tauri/target/release/Shuvcode` + +## 5) Publish locally (no CI) + +You have two viable local publish paths: + +### Option A: GitHub Releases (local upload) + +- Create a release and upload bundle artifacts + `latest.json` (updater manifest). +- Use `gh release create --repo Latitudes-Dev/shuvcode` from your machine. + +### Option B: Self-hosted updater + +- Host the full contents of `bundle/` plus `latest.json` on your own server. +- Update `plugins.updater.endpoints` to your hosting URL. + +## 6) Known local issues + +- AppImage bundling failed locally with `failed to run linuxdeploy`. + - linuxdeploy’s embedded `strip` fails on `.relr.dyn` sections; try `NO_STRIP=1` or use a newer linuxdeploy build that understands RELR. + - Install `fuse2` (or set `APPIMAGE_EXTRACT_AND_RUN=1`) plus `squashfs-tools` and `patchelf`. + - Re-run `bun run --cwd packages/desktop tauri build` after adjusting linuxdeploy/strip. + +## 7) Validation checklist + +- Launch `Shuvcode` binary, verify UI loads. +- Confirm sidecar starts (CLI server is reachable on the injected port). +- Run in-app update check; ensure it hits your Shuvcode release endpoint. +- Verify installed bundle name and identifier for each OS. diff --git a/README.md b/README.md index 04c7b53e518..6253ddd43b2 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,239 @@ +

shuvcode +

+

A fork of opencode - The AI coding agent built for the terminal.

- - - - - OpenCode logo - - + npm + GitHub release

-

The open source AI coding agent.

+ + +--- + +## Screenshots + +### Desktop App +

- Discord - npm - Build status + Desktop session with diff viewer

-[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) +*Desktop session view with AI chat, session sidebar, and real-time code diff review* + +### Mobile PWA + +

+ Mobile recent projects + Mobile sidebar menu + Mobile AI terminal view +

+ +

+ Mobile commit summary + Mobile git clone dialog + Mobile theme selector +

+ +*Mobile PWA: Recent projects, sidebar menu, AI chat with terminal, commit summary, git clone dialog, and theme selector* --- -### Installation +## Installation ```bash -# YOLO -curl -fsSL https://opencode.ai/install | bash - -# Package managers -npm i -g opencode-ai@latest # or bun/pnpm/yarn -scoop bucket add extras; scoop install extras/opencode # Windows -choco install opencode # Windows -brew install opencode # macOS and Linux -paru -S opencode-bin # Arch Linux -mise use -g opencode # Any OS -nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch +# curl install +curl -fsSL https://shuv.ai/install | bash + +# npm +npm i -g shuvcode@latest # or bun/pnpm/yarn ``` -> [!TIP] -> Remove versions older than 0.1.x before installing. +--- -### Desktop App (BETA) +## About -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). +This fork serves as an integration testing ground for upstream PRs before they are merged into the main opencode repository. We merge, test, and validate promising features and fixes to help ensure quality contributions to the upstream project. -| 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 | +The desktop app is available from the [releases page](https://github.com/Latitudes-Dev/shuvcode/releases). -```bash -# macOS (Homebrew) -brew install --cask opencode-desktop +--- + +## Merged PRs (Pending Upstream) + +The following PRs have been merged into this fork and are awaiting merge into upstream: + +| PR | Title | Author | Status | Description | +| ----------------------------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------ | ------ | ------------------------------------------------------------------------ | +| [#6476](https://github.com/sst/opencode/pull/6476) | Edit suggested changes before applying | [@dmmulroy](https://github.com/dmmulroy) | Open | Press 'e' to edit AI suggestions in your editor before accepting | +| [#6507](https://github.com/sst/opencode/pull/6507) | Optimize Ripgrep.tree() (109x faster) | [@Karavil](https://github.com/Karavil) | Open | 109x performance improvement for large repos by streaming ripgrep output | +| [#6360](https://github.com/sst/opencode/pull/6360) | Desktop: Edit Project | [@dbpolito](https://github.com/dbpolito) | Merged | Edit project name, icon color, and custom icon image in desktop sidebar | +| [#6368](https://github.com/sst/opencode/pull/6368) | Desktop: Sidebar subsessions support | [@dbpolito](https://github.com/dbpolito) | Open | Expand/collapse subsessions in sidebar with chevron indicators | +| [#6372](https://github.com/sst/opencode/pull/6372) | Desktop: Image Preview and Dedupe | [@dbpolito](https://github.com/dbpolito) | Merged | Click user attachments to preview images, dedupe file uploads | +| [#4898](https://github.com/sst/opencode/pull/4898) | Search in messages | [@OpeOginni](https://github.com/OpeOginni) | Open | Ctrl+ / to search through session messages with highlighting | +| [#4791](https://github.com/sst/opencode/pull/4791) | Bash output with ANSI | [@remorses](https://github.com/remorses) | Open | Full terminal emulation for bash output with color support | +| [#4900](https://github.com/sst/opencode/pull/4900) | Double Ctrl+C to exit | [@AmineGuitouni](https://github.com/AmineGuitouni) | Open | Require double Ctrl+C within 2 seconds to prevent accidental exits | +| [#4709](https://github.com/sst/opencode/pull/4709) | Live token usage during streaming | [@arsham](https://github.com/arsham) | Open | Real-time token tracking and display during model responses | +| [#4865](https://github.com/sst/opencode/pull/4865) | Subagents sidebar with clickable navigation | [@franlol](https://github.com/franlol) | Open | Show subagents in sidebar with click-to-navigate and parent keybind | +| [#4515](https://github.com/sst/opencode/pull/4515) | Show plugins in /status | [@spoons-and-mirrors](https://github.com/spoons-and-mirrors) | Merged | Display configured plugins in /status dialog alongside MCP/LSP servers | +| [#4411](https://github.com/sst/opencode/pull/4411) | Plugin Commands | [@spoons-and-mirrors](https://github.com/spoons-and-mirrors) | Open | Register custom `/commands` from plugins with aliases and sessionOnly | +| [#5958](https://github.com/sst/opencode/pull/5958) | AskQuestion Tool | [@iljod](https://github.com/iljod) | Open | Interactive tool for AI to collect user input via TUI/web wizard dialogs | +| [#5508](https://github.com/sst/opencode/pull/5508) | Cache management command | [@JosXa](https://github.com/JosXa) | Open | `opencode cache info` and `opencode cache clean` for plugin cache mgmt | +| [#5873](https://github.com/sst/opencode/pull/5873) | IDE integration UX improvements | [@tofunori](https://github.com/tofunori) | Open | Selection in footer, synthetic context, home screen IDE status | +| [#5917](https://github.com/sst/opencode/pull/5917) | Draggable sidebar resize | [@agustif](https://github.com/agustif) | Open | Click and drag the sidebar border to resize, width persisted to KV store | +| [#5968](https://github.com/sst/opencode/pull/5968) | Better styling for small screens | [@rekram1-node](https://github.com/rekram1-node) | Reverted | Responsive TUI layout hiding elements on short/narrow terminals | +| [#140](https://github.com/Latitudes-Dev/shuvcode/pull/140) | Toggle transparent background | [@JosXa](https://github.com/JosXa) | Open | Command palette toggle for transparent TUI background on any theme | + +_Last updated: 2026-01-04_ + +**Note:** Granular File Permissions (ariane-emory) was removed in v1.1.1 integration - upstream now provides similar functionality via PermissionNext. + +--- + +## Feature Highlights + +### Custom Server URL Settings + +Configure a custom API server URL for the desktop app: + +- **Settings dialog**: Access via command palette (Cmd/Ctrl+K → Settings) +- **URL validation**: Real-time validation with connection testing +- **Persistence**: Saved to localStorage, survives browser refresh +- **Error recovery**: Configure server URL directly from connection error pages + +Useful for self-hosted deployments or development environments. + +--- + +### GitHub App Integration + +The fork includes a dedicated GitHub App (`shuvcode-agent`) for GitHub Actions automation: + +- **Automatic PR reviews**: Trigger with `/shuvcode` or `/shuv` comments +- **Token exchange**: Secure OIDC-based authentication for CI workflows +- **Installation**: Run `shuvcode github install` to add the app to your repos + +The API is deployed to `api.shuv.ai` with Cloudflare Durable Objects for session sync. + +--- + +### Enhanced Create Project Dialog + +The "Add Project" dialog now has three tabs: + +- **Add Existing**: Browse and search folders from $HOME with fuzzy search +- **Create New**: Directory picker + project name field with path validation +- **Git Clone**: Clone from URL (coming soon) + +Features git repo detection, existing project badges, and keyboard navigation. + +--- + +### Desktop PWA Mobile Support + +The desktop web app now fully supports mobile devices as a Progressive Web App (PWA): + +- **Dynamic island handling**: Proper background color fills the notch/dynamic island area on newer iPhones +- **Mobile menu**: Full-screen navigation overlay accessible via hamburger button +- **Review overlay**: Access session changes and file viewer on mobile via the "Review" button in the header +- **Split/inline diff toggle**: Switch between side-by-side and inline diff views in the review panel +- **Responsive layout**: Timeline rail hidden on mobile, session pane takes full width + +Install as PWA on iOS: Open in Safari → Share → Add to Home Screen + +--- + +### IDE Integration (Cursor/VSCode) + +Connect to Cursor, VSCode, or other supported IDEs for enhanced workflow: + +- **Live text selection** from your editor is displayed in the TUI footer +- **Selection context** is automatically included in prompts (invisible to you, but sent to the model) +- **IDE status** shown on the home screen footer +- **Diff view** support for file edits (open diffs directly in your IDE) + +Configure in `opencode.json`: + +```jsonc +{ + "ide": { + "lockfile_dir": "~/.cursor/opencode/", + "auth_header_name": "x-opencode-auth", + }, +} ``` -#### Installation Directory +Supported IDEs: Cursor, VSCode, VSCode Insiders, VSCodium, Windsurf + +--- -The install script respects the following priority order for the installation path: +### Add Existing Project Dialog -1. `$OPENCODE_INSTALL_DIR` - Custom installation directory -2. `$XDG_BIN_DIR` - XDG Base Directory Specification compliant path -3. `$HOME/bin` - Standard user binary directory (if exists or can be created) -4. `$HOME/.opencode/bin` - Default fallback +The desktop "Create project" button now opens an improved "Add Project" dialog with two tabs: -```bash -# Examples -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 +- **Add Existing**: Browse and search folders from your home directory with fuzzy search, see git repo indicators, and add existing projects with one click +- **Create New**: Original path input for creating new project directories + +The folder browser scans up to 2 levels deep from `$HOME`, prioritizes git repositories, and shows which folders are already added as projects. + +--- + +### Desktop Image Preview + +The desktop file viewer now displays actual image previews for PNG, JPG, GIF, and WEBP files instead of showing raw base64 text. Images are centered and scaled to fit within the viewport with scrolling support for large images. SVG files are excluded from image preview and render as syntax-highlighted XML code. + +--- + +### TUI Spinner Styles + +Choose from 60+ animated spinner styles for tool execution indicators. Access via the command palette with `Change spinner style`. Your selection is persisted across sessions. + +Available styles include braille patterns, block animations, geometric shapes, and creative concepts like moon phases, clock sweeps, and bouncing balls. + +You can also adjust the animation speed via `Change spinner speed` in the command palette. Options range from 20ms (fastest) to 500ms (slowest), with 60ms as the default. + +--- + +### TUI Layout Density + +The TUI automatically adapts its vertical spacing for small terminals (< 28 rows). Configure via `tui.density`: + +- `auto` (default): Switches to compact mode on small terminals +- `comfortable`: Standard spacing with footer and hints +- `compact`: Reduced padding, hides footer and secondary hints + +Toggle density from the command palette or set in config: + +```jsonc +{ + "tui": { + "density": "auto", + }, +} +``` + +--- + +### AskQuestion Tool (Experimental) + +Enable the AI to pause and ask structured questions via a wizard UI. Available in both TUI and web app. + +Enable in `opencode.json`: + +```jsonc +{ + "experimental": { + "askquestion_tool": true, + }, +} ``` +Features: +- Wizard-style multi-question dialogs with single/multi-select options +- Custom text input for freeform responses +- Keyboard navigation (1-8 quick select, Tab between questions, Enter to confirm) +- Works across TUI and web app with session resume support + +--- + ### Agents OpenCode includes two built-in agents you can switch between with the `Tab` key. @@ -83,6 +249,25 @@ This is used internally and can be invoked using `@general` in messages. Learn more about [agents](https://opencode.ai/docs/agents). +### Sessions Sidebar + +A NERDTree-style sidebar for managing sessions. Toggle with `ctrl+n`. + +| Key | Action | +| -------------- | ---------------------------- | +| `j/k` or `↑/↓` | Move cursor | +| `Enter` or `o` | Open session / Toggle expand | +| `O` | Expand all children | +| `x` | Collapse parent | +| `X` | Collapse all | +| `p` | Go to parent | +| `g/G` | Jump to top/bottom | +| `n` | New session | +| `r` | Rename session | +| `d` | Delete session | +| `?` | Show help | +| `q` or `Esc` | Close sidebar | + ### Documentation For more info on how to configure OpenCode [**head over to our docs**](https://opencode.ai/docs). diff --git a/TAURI_DESKTOP_FOLLOWUPS.md b/TAURI_DESKTOP_FOLLOWUPS.md new file mode 100644 index 00000000000..65ecd6b8799 --- /dev/null +++ b/TAURI_DESKTOP_FOLLOWUPS.md @@ -0,0 +1,10 @@ +# Shuvcode Desktop (Tauri) Follow-ups + +- Update the Tauri updater public key to the Shuvcode signing key in `packages/desktop/src-tauri/tauri.prod.conf.json`. +- Confirm the fork’s release workflow uploads `latest.json` and uses the Shuvcode repo endpoint for updater artifacts. +- Ensure the CI artifact name for the sidecar is `shuvcode-cli` (matches `packages/desktop/scripts/prepare.ts`). +- Verify all sidecar binaries exist for targets in `packages/desktop/scripts/utils.ts` (especially Linux arm64). +- Validate bundle naming in CI now that the product name is Shuvcode (script expects `Shuvcode*` in `packages/desktop/scripts/copy-bundles.ts`). +- Resolve AppImage bundling on Linux: linuxdeploy’s embedded `strip` fails on `.relr.dyn` sections; try `NO_STRIP=1` or a newer linuxdeploy build, or wrap linuxdeploy to use `/usr/bin/strip`. +- Check macOS/Windows signing identities and entitlements to match the new bundle identifiers (`dev.shuvcode.desktop`). +- Run a full desktop smoke test: `bun run predev` then `bun run tauri dev`, confirm sidecar launch + update flow. diff --git a/bun.lock b/bun.lock index 0a82517145d..cbb55aa745b 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "opencode", "dependencies": { "@aws-sdk/client-s3": "3.933.0", + "@aws-sdk/credential-providers": "3.964.0", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", @@ -22,7 +23,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -65,12 +66,13 @@ "typescript": "catalog:", "vite": "catalog:", "vite-plugin-icons-spritesheet": "3.0.1", + "vite-plugin-pwa": "1.2.0", "vite-plugin-solid": "catalog:", }, }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -98,7 +100,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -125,7 +127,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -149,7 +151,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -172,8 +174,8 @@ }, }, "packages/desktop": { - "name": "@opencode-ai/desktop", - "version": "1.1.4", + "name": "@shuvcode/desktop", + "version": "1.1.4-1", "dependencies": { "@opencode-ai/app": "workspace:*", "@solid-primitives/storage": "catalog:", @@ -201,7 +203,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -230,7 +232,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -246,7 +248,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.1.4", + "version": "1.1.4-1", "bin": { "opencode": "./bin/opencode", }, @@ -301,6 +303,7 @@ "decimal.js": "10.5.0", "diff": "catalog:", "fuzzysort": "3.1.0", + "ghostty-opentui": "1.3.7", "gray-matter": "4.0.3", "hono": "catalog:", "hono-openapi": "catalog:", @@ -349,7 +352,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -369,7 +372,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.1.4", + "version": "1.1.4-1", "devDependencies": { "@hey-api/openapi-ts": "0.88.1", "@tsconfig/node22": "catalog:", @@ -380,7 +383,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -393,7 +396,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -431,7 +434,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "zod": "catalog:", }, @@ -442,7 +445,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -478,6 +481,7 @@ "tree-sitter-bash", ], "patchedDependencies": { + "ghostty-opentui@1.3.7": "patches/ghostty-opentui@1.3.7.patch", "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch", }, "overrides": { @@ -581,6 +585,8 @@ "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + "@apideck/better-ajv-errors": ["@apideck/better-ajv-errors@0.3.6", "", { "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA=="], + "@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.13.0", "", {}, "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw=="], @@ -617,27 +623,35 @@ "@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-cognito-identity": ["@aws-sdk/client-cognito-identity@3.964.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.964.0", "@aws-sdk/credential-provider-node": "3.964.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.964.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.964.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@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.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-a3/hoL31S1fAd3jIPqDvF8P5Aybev+73K3d4zaa8lEBt5M6eeBpebakcJxsu42RTGCb26+3OpHs3VG4bitr5gw=="], + "@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-sso": ["@aws-sdk/client-sso@3.964.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.964.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.964.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.964.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@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.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-IenVyY8Io2CwBgmS22xk/H5LibmSbvLnPA9oFqLORO6Ji1Ks8z/ow+ud/ZurVjFekz3LD/uxVFX3ZKGo6N7Byw=="], "@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.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-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.964.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-R2/BOTifFhKPDNuKeLiQkOjgusqVffNy6mchbZMR0C4ucHZ5cWfSyJhn7pXIU6+/aMs/NbkuSttvxGy/fbyJ6g=="], + + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jWNSXOOBMYuxzI2rXi8x91YL07dhomyGzzh0CdaLej0LRmknmDrZcZNkVpa7Fredy1PFcmOlokwCS5PmZMN8ZQ=="], + + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-up7dl6vcaoXuYSwGXDvx8RnF8Lwj3jGChhyUR7krZOXLarIfUUN3ILOZnVNK5s/HnVNkEILlkdPvjhr9LVC1/Q=="], - "@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.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/credential-provider-env": "3.964.0", "@aws-sdk/credential-provider-http": "3.964.0", "@aws-sdk/credential-provider-login": "3.964.0", "@aws-sdk/credential-provider-process": "3.964.0", "@aws-sdk/credential-provider-sso": "3.964.0", "@aws-sdk/credential-provider-web-identity": "3.964.0", "@aws-sdk/nested-clients": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-t4FN9qTWU4nXDU6EQ6jopvyhXw0dbQ3n+3g6x5hmc1ECFAqA+xmFd1i5LljdZCi79cUXHduQWwvW8RJHMf0qJw=="], - "@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-login": ["@aws-sdk/credential-provider-login@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/nested-clients": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-c64dmTizMkJXDRzN3NYPTmUpKxegr5lmLOYPeQ60Zcbft6HFwPme8Gwy8pNxO4gG1fw6Ja2Vu6fZuSTn8aDFOQ=="], "@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-process": ["@aws-sdk/credential-provider-process@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-HaTLKqj3jeZY88E/iBjsNJsXgmRTTT7TghqeRiF8FKb/7UY1xEvasBO0c1xqfOye8dsyt35nTfTTyIsd/CBfww=="], - "@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-sso": ["@aws-sdk/credential-provider-sso@3.964.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.964.0", "@aws-sdk/core": "3.964.0", "@aws-sdk/token-providers": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-oR78TjSpjVf1IpPWQnGHEGqlnQs+K4f5nCxLK2P6JDPprXay6oknsoSiU4x2urav6VCyMPMC9KTCGjBoFKUIxQ=="], - "@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/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/nested-clients": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-07JQDmbjZjOt3nL/j1wTcvQqjmPkynQYftUV/ooZ+qTbmJXFbCBdal1VCElyeiu0AgBq9dfhw0rBBcbND1ZMlA=="], + + "@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.964.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.964.0", "@aws-sdk/core": "3.964.0", "@aws-sdk/credential-provider-cognito-identity": "3.964.0", "@aws-sdk/credential-provider-env": "3.964.0", "@aws-sdk/credential-provider-http": "3.964.0", "@aws-sdk/credential-provider-ini": "3.964.0", "@aws-sdk/credential-provider-login": "3.964.0", "@aws-sdk/credential-provider-node": "3.964.0", "@aws-sdk/credential-provider-process": "3.964.0", "@aws-sdk/credential-provider-sso": "3.964.0", "@aws-sdk/credential-provider-web-identity": "3.964.0", "@aws-sdk/nested-clients": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-XUL0QypiD+g8ZmoMTulxtIJgibE7AHAmDjh/tmiW44V2z2KApCizQqqKFVdX9qsVF4bqS3ROIRJGckIBdOmlEw=="], "@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=="], @@ -659,13 +673,13 @@ "@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/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/nested-clients": ["@aws-sdk/nested-clients@3.964.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.964.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.964.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.964.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@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.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ql+ftRwjyZkZeG3qbrRJFVmNR0id83WEUqhFVjvrQMWspNApBhz0Ar4YVSn7Uv0QaKkaR7ALPtmdMzFr3/E4bQ=="], "@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/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/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/token-providers": ["@aws-sdk/token-providers@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/nested-clients": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-UqouLQbYepZnMFJGB/DVpA5GhF9uT98vNWSMz9PVbhgEPUKa73FECRT6YFZvZOh8kA+0JiENrnmS6d93I70ykQ=="], "@aws-sdk/types": ["@aws-sdk/types@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A=="], @@ -725,6 +739,10 @@ "@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-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="], + + "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="], + "@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.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], @@ -737,6 +755,8 @@ "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], + "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="], + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="], "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], @@ -747,22 +767,146 @@ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="], + "@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.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="], + + "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="], + + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="], + + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="], + + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="], + + "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w=="], + + "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="], + + "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww=="], + "@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=="], "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="], + "@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg=="], + + "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="], + + "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="], + + "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="], + + "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="], + + "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="], + + "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], + + "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="], + + "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="], + + "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="], + + "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="], + + "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="], + + "@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="], + + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="], + + "@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="], + + "@babel/plugin-transform-explicit-resource-management": ["@babel/plugin-transform-explicit-resource-management@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ=="], + + "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="], + + "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="], + + "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="], + + "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="], + + "@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="], + + "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="], + + "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="], + + "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="], + + "@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@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-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="], + "@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-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="], + + "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@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-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="], + + "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="], + + "@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="], + + "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="], + + "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="], + + "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="], + + "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="], + + "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="], + + "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="], + + "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], + + "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="], + + "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="], + + "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="], + "@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-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="], + + "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="], + + "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="], + + "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="], + + "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="], + + "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="], + + "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="], + + "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="], + "@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/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="], + + "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="], + + "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="], + + "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="], + + "@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="], + + "@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA=="], + "@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.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], @@ -1171,8 +1315,6 @@ "@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"], - "@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"], - "@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"], "@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"], @@ -1413,6 +1555,14 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], + "@rollup/plugin-babel": ["@rollup/plugin-babel@5.3.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.10.4", "@rollup/pluginutils": "^3.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", "rollup": "^1.20.0||^2.0.0" }, "optionalPeers": ["@types/babel__core"] }, "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q=="], + + "@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@15.3.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-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA=="], + + "@rollup/plugin-replace": ["@rollup/plugin-replace@2.4.2", "", { "dependencies": { "@rollup/pluginutils": "^3.1.0", "magic-string": "^0.25.7" }, "peerDependencies": { "rollup": "^1.20.0 || ^2.0.0" } }, "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg=="], + + "@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=="], + "@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=="], "@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=="], @@ -1477,6 +1627,8 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + "@shuvcode/desktop": ["@shuvcode/desktop@workspace:packages/desktop"], + "@sindresorhus/is": ["@sindresorhus/is@7.1.1", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="], "@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=="], @@ -1501,7 +1653,7 @@ "@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=="], - "@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=="], + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA=="], "@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=="], @@ -1541,7 +1693,7 @@ "@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=="], - "@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=="], + "@smithy/property-provider": ["@smithy/property-provider@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA=="], "@smithy/protocol-http": ["@smithy/protocol-http@5.3.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ=="], @@ -1645,6 +1797,8 @@ "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + "@surma/rollup-plugin-off-main-thread": ["@surma/rollup-plugin-off-main-thread@2.2.3", "", { "dependencies": { "ejs": "^3.1.6", "json5": "^2.2.0", "magic-string": "^0.25.0", "string.prototype.matchall": "^4.0.6" } }, "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ=="], + "@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=="], @@ -1813,6 +1967,8 @@ "@types/react": ["@types/react@18.0.25", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g=="], + "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], + "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="], @@ -1823,6 +1979,8 @@ "@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=="], @@ -1959,6 +2117,8 @@ "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="], + "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=="], @@ -1983,6 +2143,12 @@ "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-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="], + + "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="], + + "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="], + "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=="], @@ -2151,6 +2317,8 @@ "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], + "common-tags": ["common-tags@1.8.2", "", {}, "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA=="], + "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=="], "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=="], @@ -2173,6 +2341,8 @@ "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], + "core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="], + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="], @@ -2187,6 +2357,8 @@ "crossws": ["crossws@0.4.1", "", { "peerDependencies": { "srvx": ">=0.7.1" }, "optionalPeers": ["srvx"] }, "sha512-E7WKBcHVhAVrY6JYD5kteNqVq1GSZxqGrdSiwXR9at+XHi43HJoCQKXcCczR5LBnBquFZPsB3o7HklulKoBU5w=="], + "crypto-random-string": ["crypto-random-string@2.0.0", "", {}, "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="], + "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=="], @@ -2295,6 +2467,8 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], + "electron-to-chromium": ["electron-to-chromium@1.5.259", "", {}, "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ=="], "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], @@ -2363,6 +2537,8 @@ "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=="], @@ -2407,6 +2583,8 @@ "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=="], @@ -2415,6 +2593,8 @@ "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=="], + "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "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=="], @@ -2451,7 +2631,7 @@ "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-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], @@ -2485,6 +2665,8 @@ "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + "get-own-enumerable-property-symbols": ["get-own-enumerable-property-symbols@3.0.2", "", {}, "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g=="], + "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=="], @@ -2495,6 +2677,8 @@ "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + "ghostty-opentui": ["ghostty-opentui@1.3.7", "", { "dependencies": { "strip-ansi": "^7.1.2" }, "peerDependencies": { "@opentui/core": "*" }, "optionalPeers": ["@opentui/core"] }, "sha512-tXlVrFKMiS+VNm48OwQtCefP7i85o04wv2S/NPR5bIzv4yAl2//q7CBa8JEv9bL+5jpZsfMm6z8VJGrTq6Xjvg=="], + "ghostty-web": ["ghostty-web@0.3.0", "", {}, "sha512-SAdSHWYF20GMZUB0n8kh1N6Z4ljMnuUqT8iTB2n5FAPswEV10MejEpLlhW/769GL5+BQa1NYwEg9y/XCckV5+A=="], "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], @@ -2627,6 +2811,8 @@ "iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], + "idb": ["idb@7.1.1", "", {}, "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="], + "ieee754": ["ieee754@1.1.13", "", {}, "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="], "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], @@ -2705,12 +2891,16 @@ "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-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-obj": ["is-obj@1.0.1", "", {}, "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="], + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], @@ -2719,6 +2909,8 @@ "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-regexp": ["is-regexp@1.0.0", "", {}, "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA=="], + "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=="], @@ -2755,6 +2947,8 @@ "jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="], + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], + "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=="], @@ -2789,6 +2983,8 @@ "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="], + "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=="], "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=="], @@ -2813,6 +3009,8 @@ "leac": ["leac@0.6.0", "", {}, "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="], + "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], + "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=="], "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="], @@ -2843,6 +3041,8 @@ "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], + "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], "lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="], @@ -2861,6 +3061,8 @@ "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="], + "loglevelnext": ["loglevelnext@6.0.0", "", {}, "sha512-FDl1AI2sJGjHHG3XKJd6sG3/6ncgiGCQ0YkW46nxe7SfqQq6hujd9CvFXIXtkGBUN83KPZ2KSOJK8q5P0bSSRQ=="], "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], @@ -3265,6 +3467,8 @@ "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=="], + "pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="], + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], @@ -3295,6 +3499,8 @@ "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], + "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "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=="], @@ -3341,6 +3547,10 @@ "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=="], + "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], + + "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="], + "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=="], @@ -3349,6 +3559,12 @@ "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=="], + "regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="], + + "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], + + "regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="], + "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=="], @@ -3383,6 +3599,8 @@ "remeda": ["remeda@2.26.0", "", { "dependencies": { "type-fest": "^4.41.0" } }, "sha512-lmNNwtaC6Co4m0WTTNoZ/JlpjEqAjPZO0+czC9YVRQUpkbS4x8Hmh+Mn9HPfJfiXqUQ5IXXgSXSOB2pBKAytdA=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="], "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=="], @@ -3443,6 +3661,8 @@ "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], + "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], + "seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="], "seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="], @@ -3491,6 +3711,8 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "smob": ["smob@1.5.0", "", {}, "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig=="], + "smol-toml": ["smol-toml@1.5.2", "", {}, "sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ=="], "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=="], @@ -3505,12 +3727,14 @@ "solid-use": ["solid-use@0.9.1", "", { "peerDependencies": { "solid-js": "^1.7" } }, "sha512-UwvXDVPlrrbj/9ewG9ys5uL2IO4jSiwys2KPzK4zsnAcmEl7iDafZWW1Mo4BSEWOmQCGK6IvpmGHo1aou8iOFw=="], - "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "sourcemap-codec": ["sourcemap-codec@1.4.8", "", {}, "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="], + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], @@ -3561,6 +3785,8 @@ "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.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], + "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=="], @@ -3571,12 +3797,16 @@ "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=="], + "stringify-object": ["stringify-object@3.3.0", "", { "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", "is-regexp": "^1.0.0" } }, "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw=="], + "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-comments": ["strip-comments@2.0.1", "", {}, "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw=="], + "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=="], @@ -3607,6 +3837,10 @@ "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=="], + "temp-dir": ["temp-dir@2.0.0", "", {}, "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg=="], + + "tempy": ["tempy@0.6.0", "", { "dependencies": { "is-stream": "^2.0.0", "temp-dir": "^2.0.0", "type-fest": "^0.16.0", "unique-string": "^2.0.0" } }, "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw=="], + "terracotta": ["terracotta@1.0.6", "", { "dependencies": { "solid-use": "^0.9.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-yVrmT/Lg6a3tEbeYEJH8ksb1PYkR5FA9k5gr1TchaSNIiA2ZWs5a+koEbePXwlBP0poaV7xViZ/v50bQFcMgqw=="], "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=="], @@ -3715,14 +3949,24 @@ "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], + "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], + + "unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="], + + "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="], + "unicode-properties": ["unicode-properties@1.4.1", "", { "dependencies": { "base64-js": "^1.3.0", "unicode-trie": "^2.0.0" } }, "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg=="], + "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.2.0", "", {}, "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ=="], + "unicode-trie": ["unicode-trie@2.0.0", "", { "dependencies": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" } }, "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ=="], "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=="], + "unique-string": ["unique-string@2.0.0", "", { "dependencies": { "crypto-random-string": "^2.0.0" } }, "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg=="], + "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.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], @@ -3755,6 +3999,8 @@ "unzip-stream": ["unzip-stream@0.3.4", "", { "dependencies": { "binary": "^0.3.0", "mkdirp": "^0.5.1" } }, "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw=="], + "upath": ["upath@1.2.0", "", {}, "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="], + "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=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -3791,6 +4037,8 @@ "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-pwa": ["vite-plugin-pwa@1.2.0", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.4.0", "workbox-window": "^7.4.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw=="], + "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=="], @@ -3829,6 +4077,38 @@ "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], + "workbox-background-sync": ["workbox-background-sync@7.4.0", "", { "dependencies": { "idb": "^7.0.1", "workbox-core": "7.4.0" } }, "sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w=="], + + "workbox-broadcast-update": ["workbox-broadcast-update@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA=="], + + "workbox-build": ["workbox-build@7.4.0", "", { "dependencies": { "@apideck/better-ajv-errors": "^0.3.1", "@babel/core": "^7.24.4", "@babel/preset-env": "^7.11.0", "@babel/runtime": "^7.11.2", "@rollup/plugin-babel": "^5.2.0", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^2.4.1", "@rollup/plugin-terser": "^0.4.3", "@surma/rollup-plugin-off-main-thread": "^2.2.3", "ajv": "^8.6.0", "common-tags": "^1.8.0", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "^9.0.1", "glob": "^11.0.1", "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", "rollup": "^2.79.2", "source-map": "^0.8.0-beta.0", "stringify-object": "^3.3.0", "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", "workbox-background-sync": "7.4.0", "workbox-broadcast-update": "7.4.0", "workbox-cacheable-response": "7.4.0", "workbox-core": "7.4.0", "workbox-expiration": "7.4.0", "workbox-google-analytics": "7.4.0", "workbox-navigation-preload": "7.4.0", "workbox-precaching": "7.4.0", "workbox-range-requests": "7.4.0", "workbox-recipes": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0", "workbox-streams": "7.4.0", "workbox-sw": "7.4.0", "workbox-window": "7.4.0" } }, "sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA=="], + + "workbox-cacheable-response": ["workbox-cacheable-response@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ=="], + + "workbox-core": ["workbox-core@7.4.0", "", {}, "sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ=="], + + "workbox-expiration": ["workbox-expiration@7.4.0", "", { "dependencies": { "idb": "^7.0.1", "workbox-core": "7.4.0" } }, "sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw=="], + + "workbox-google-analytics": ["workbox-google-analytics@7.4.0", "", { "dependencies": { "workbox-background-sync": "7.4.0", "workbox-core": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0" } }, "sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ=="], + + "workbox-navigation-preload": ["workbox-navigation-preload@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w=="], + + "workbox-precaching": ["workbox-precaching@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0" } }, "sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg=="], + + "workbox-range-requests": ["workbox-range-requests@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw=="], + + "workbox-recipes": ["workbox-recipes@7.4.0", "", { "dependencies": { "workbox-cacheable-response": "7.4.0", "workbox-core": "7.4.0", "workbox-expiration": "7.4.0", "workbox-precaching": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0" } }, "sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ=="], + + "workbox-routing": ["workbox-routing@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ=="], + + "workbox-strategies": ["workbox-strategies@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg=="], + + "workbox-streams": ["workbox-streams@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0", "workbox-routing": "7.4.0" } }, "sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg=="], + + "workbox-sw": ["workbox-sw@7.4.0", "", {}, "sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw=="], + + "workbox-window": ["workbox-window@7.4.0", "", { "dependencies": { "@types/trusted-types": "^2.0.2", "workbox-core": "7.4.0" } }, "sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw=="], + "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.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=="], @@ -3931,6 +4211,8 @@ "@ai-sdk/xai/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.29", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="], + "@apideck/better-ajv-errors/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=="], + "@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=="], "@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], @@ -3939,6 +4221,8 @@ "@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/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "@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=="], @@ -3951,215 +4235,527 @@ "@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-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], - "@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-cognito-identity/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.964.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.964.0", "@aws-sdk/credential-provider-http": "3.964.0", "@aws-sdk/credential-provider-ini": "3.964.0", "@aws-sdk/credential-provider-process": "3.964.0", "@aws-sdk/credential-provider-sso": "3.964.0", "@aws-sdk/credential-provider-web-identity": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-FHxDXPOj888/qc/X8s0x4aUBdp4Y3k9VePRehUJBWRhhTsAyuIJis5V0iQeY1qvtqHXYa2qd1EZHGJ3bTjHxSw=="], - "@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/client-cognito-identity/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA=="], - "@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/client-cognito-identity/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ=="], - "@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/client-cognito-identity/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA=="], - "@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/client-cognito-identity/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/QyBl8WLNtqw3ucyAggumQXVCi8GRxaDGE1ElyYMmacfiwHl37S9y8JVW/QLL1lIEXGcsrhMUKV3pyFJFALA7w=="], - "@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/client-cognito-identity/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A=="], - "@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/client-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@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/client-cognito-identity/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw=="], - "@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/client-cognito-identity/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw=="], - "@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/client-cognito-identity/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.964.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-jgob8Z/bZIh1dwEgLqE12q+aCf0ieLy7anT8bWpqMijMJqsnrPBToa7smSykfom9YHrdOgrQhXswMpE75dzLRw=="], - "@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/client-cognito-identity/@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="], - "@azure/core-http/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="], + "@aws-sdk/client-cognito-identity/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], - "@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/client-cognito-identity/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], - "@azure/core-http/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "@aws-sdk/client-cognito-identity/@smithy/hash-node": ["@smithy/hash-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw=="], - "@azure/core-http/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + "@aws-sdk/client-cognito-identity/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@aws-sdk/client-cognito-identity/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], - "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "@aws-sdk/client-cognito-identity/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.17", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg=="], - "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@aws-sdk/client-cognito-identity/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], - "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@aws-sdk/client-cognito-identity/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], - "@bufbuild/protoplugin/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="], + "@aws-sdk/client-cognito-identity/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], - "@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "@aws-sdk/client-cognito-identity/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.16", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ=="], - "@hono/zod-validator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-cognito-identity/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.19", "", { "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="], - "@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=="], + "@aws-sdk/client-cognito-identity/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "@jimp/plugin-blit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-cognito-identity/@smithy/util-retry": ["@smithy/util-retry@4.2.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg=="], - "@jimp/plugin-circle/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], - "@jimp/plugin-color/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA=="], - "@jimp/plugin-contain/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ=="], - "@jimp/plugin-cover/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA=="], - "@jimp/plugin-crop/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/QyBl8WLNtqw3ucyAggumQXVCi8GRxaDGE1ElyYMmacfiwHl37S9y8JVW/QLL1lIEXGcsrhMUKV3pyFJFALA7w=="], - "@jimp/plugin-displace/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A=="], - "@jimp/plugin-fisheye/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@jimp/plugin-flip/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw=="], - "@jimp/plugin-mask/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw=="], - "@jimp/plugin-print/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.964.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-jgob8Z/bZIh1dwEgLqE12q+aCf0ieLy7anT8bWpqMijMJqsnrPBToa7smSykfom9YHrdOgrQhXswMpE75dzLRw=="], - "@jimp/plugin-quantize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="], - "@jimp/plugin-resize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], - "@jimp/plugin-rotate/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], - "@jimp/plugin-threshold/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@smithy/hash-node": ["@smithy/hash-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw=="], - "@jimp/types/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="], - "@jsx-email/cli/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "@aws-sdk/client-sso/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.17", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], - "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/client-sso/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "@octokit/auth-app/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + "@aws-sdk/client-sso/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.16", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.19", "", { "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "@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=="], + "@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg=="], - "@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=="], + "@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=="], - "@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@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=="], - "@octokit/core/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + "@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=="], - "@octokit/endpoint/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@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=="], - "@octokit/endpoint/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + "@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=="], - "@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=="], + "@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=="], - "@octokit/graphql/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "@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=="], - "@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=="], + "@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=="], - "@octokit/oauth-methods/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + "@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=="], - "@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=="], + "@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=="], - "@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=="], + "@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=="], - "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "@aws-sdk/core/@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=="], - "@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=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "@aws-sdk/credential-provider-cognito-identity/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@octokit/plugin-retry/@octokit/types": ["@octokit/types@6.41.0", "", { "dependencies": { "@octokit/openapi-types": "^12.11.0" } }, "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg=="], + "@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], - "@octokit/request/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@aws-sdk/credential-provider-env/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@octokit/request/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + "@aws-sdk/credential-provider-env/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@aws-sdk/credential-provider-http/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], - "@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=="], + "@aws-sdk/credential-provider-http/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@octokit/rest/@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], + "@aws-sdk/credential-provider-http/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], - "@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="], + "@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], - "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@aws-sdk/credential-provider-http/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "@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=="], + "@aws-sdk/credential-provider-http/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], + "@aws-sdk/credential-provider-http/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@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=="], + "@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], - "@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=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], - "@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=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="], + "@aws-sdk/credential-provider-ini/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], - "@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=="], + "@aws-sdk/credential-provider-ini/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@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=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], - "@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=="], + "@aws-sdk/credential-provider-login/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], - "@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=="], + "@aws-sdk/credential-provider-login/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "@aws-sdk/credential-provider-login/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], - "@protobuf-ts/plugin/typescript": ["typescript@3.9.10", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q=="], + "@aws-sdk/credential-provider-login/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], - "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@aws-sdk/credential-provider-node/@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=="], - "@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=="], + "@aws-sdk/credential-provider-node/@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=="], - "@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=="], + "@aws-sdk/credential-provider-node/@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=="], - "@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=="], + "@aws-sdk/credential-provider-node/@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=="], - "@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=="], + "@aws-sdk/credential-provider-node/@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=="], - "@slack/bolt/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "@aws-sdk/credential-provider-node/@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=="], - "@slack/oauth/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], + "@aws-sdk/credential-provider-node/@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=="], - "@slack/socket-mode/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], + "@aws-sdk/credential-provider-node/@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=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], + + "@aws-sdk/credential-provider-process/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-process/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], + + "@aws-sdk/credential-provider-sso/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-sso/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], + + "@aws-sdk/credential-provider-web-identity/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-web-identity/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@aws-sdk/credential-providers/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], + + "@aws-sdk/credential-providers/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.964.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.964.0", "@aws-sdk/credential-provider-http": "3.964.0", "@aws-sdk/credential-provider-ini": "3.964.0", "@aws-sdk/credential-provider-process": "3.964.0", "@aws-sdk/credential-provider-sso": "3.964.0", "@aws-sdk/credential-provider-web-identity": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-FHxDXPOj888/qc/X8s0x4aUBdp4Y3k9VePRehUJBWRhhTsAyuIJis5V0iQeY1qvtqHXYa2qd1EZHGJ3bTjHxSw=="], + + "@aws-sdk/credential-providers/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], + + "@aws-sdk/credential-providers/@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="], + + "@aws-sdk/credential-providers/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/credential-providers/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@aws-sdk/credential-providers/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.964.0", "", { "dependencies": { "@aws-sdk/core": "3.964.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/QyBl8WLNtqw3ucyAggumQXVCi8GRxaDGE1ElyYMmacfiwHl37S9y8JVW/QLL1lIEXGcsrhMUKV3pyFJFALA7w=="], + + "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A=="], + + "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], + + "@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw=="], + + "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw=="], + + "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.964.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.964.0", "@aws-sdk/types": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-jgob8Z/bZIh1dwEgLqE12q+aCf0ieLy7anT8bWpqMijMJqsnrPBToa7smSykfom9YHrdOgrQhXswMpE75dzLRw=="], + + "@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="], + + "@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw=="], + + "@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="], + + "@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg=="], + + "@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.17", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg=="], + + "@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/nested-clients/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], + + "@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], + + "@aws-sdk/nested-clients/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.16", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ=="], + + "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.19", "", { "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA=="], + + "@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="], + + "@aws-sdk/nested-clients/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], + + "@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg=="], + + "@aws-sdk/token-providers/@aws-sdk/core": ["@aws-sdk/core@3.964.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-1gIfbt0KRxI8am1UYFcIxQ5QKb22JyN3k52sxyrKXJYC8Knn/rTUAZbYti45CfETe5PLadInGvWqClwGRlZKNg=="], + + "@aws-sdk/token-providers/@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], + + "@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/token-providers/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@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=="], + + "@azure/core-http/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="], + + "@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=="], + + "@azure/core-http/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "@azure/core-http/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + + "@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=="], + + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "@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/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-regexp-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/preset-env/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@bufbuild/protoplugin/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="], + + "@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=="], + + "@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@jimp/plugin-blit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-circle/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-color/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-contain/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-cover/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-crop/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-displace/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-fisheye/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-flip/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-mask/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-print/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-quantize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-resize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-rotate/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/plugin-threshold/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jimp/types/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@jsx-email/cli/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "@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=="], + + "@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=="], + + "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@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=="], + + "@octokit/auth-app/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@octokit/core/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + + "@octokit/endpoint/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@octokit/endpoint/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + + "@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=="], + + "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + + "@octokit/plugin-retry/@octokit/types": ["@octokit/types@6.41.0", "", { "dependencies": { "@octokit/openapi-types": "^12.11.0" } }, "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg=="], + + "@octokit/request/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@octokit/request/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + + "@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@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=="], + + "@octokit/rest/@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], + + "@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/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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + + "@protobuf-ts/plugin/typescript": ["typescript@3.9.10", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q=="], + + "@rollup/plugin-babel/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="], + + "@rollup/plugin-babel/rollup": ["rollup@2.79.2", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ=="], + + "@rollup/plugin-replace/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="], + + "@rollup/plugin-replace/magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="], + + "@rollup/plugin-replace/rollup": ["rollup@2.79.2", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ=="], + + "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@shuvcode/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=="], + + "@shuvcode/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], + + "@slack/bolt/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + + "@slack/oauth/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], + + "@slack/socket-mode/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], "@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=="], @@ -4171,6 +4767,22 @@ "@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=="], + "@smithy/credential-provider-imds/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@smithy/credential-provider-imds/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@smithy/node-config-provider/@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=="], + + "@smithy/property-provider/@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], + + "@smithy/util-defaults-mode-browser/@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=="], + + "@smithy/util-defaults-mode-node/@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=="], + + "@smithy/util-defaults-mode-node/@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=="], + "@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=="], "@solidjs/start/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], @@ -4179,6 +4791,8 @@ "@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=="], + "@surma/rollup-plugin-off-main-thread/magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="], + "@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=="], @@ -4225,6 +4839,8 @@ "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=="], + "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], @@ -4253,6 +4869,10 @@ "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=="], + "esbuild-plugin-copy/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=="], + + "estree-util-to-js/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], "express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], @@ -4263,6 +4883,8 @@ "express/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], @@ -4349,129 +4971,381 @@ "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "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=="], + + "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + + "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "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/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + + "sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "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=="], + + "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/whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="], + + "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=="], + + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + + "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "tempy/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "tempy/type-fest": ["type-fest@0.16.0", "", {}, "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg=="], + + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], + + "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=="], + + "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=="], + + "type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "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=="], + + "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "utif2/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "vitest/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + + "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=="], + + "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=="], + + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "workbox-build/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=="], + + "workbox-build/pretty-bytes": ["pretty-bytes@5.6.0", "", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="], + + "workbox-build/rollup": ["rollup@2.79.2", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], + + "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + + "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "zod-to-ts/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@actions/artifact/@actions/core/@actions/exec": ["@actions/exec@2.0.0", "", { "dependencies": { "@actions/io": "^2.0.0" } }, "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw=="], + + "@actions/core/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + + "@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=="], + + "@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=="], + + "@apideck/better-ajv-errors/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="], + + "@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="], + + "@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.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=="], + + "@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/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=="], + + "@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=="], + + "@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-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], + + "@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], + + "@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="], + + "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/client-cognito-identity/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/client-cognito-identity/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/client-cognito-identity/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], + + "@aws-sdk/client-cognito-identity/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/client-cognito-identity/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/client-cognito-identity/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], + + "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], + + "@aws-sdk/client-sso/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], + + "@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="], + + "@aws-sdk/client-sso/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/client-sso/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], + + "@aws-sdk/client-sso/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/client-sso/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/client-sso/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], + + "@aws-sdk/client-sts/@aws-sdk/core/@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@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=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@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=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], + + "@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "safe-push-apply/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@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=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@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=="], - "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@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=="], - "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@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=="], - "sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], - "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=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], - "shiki/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "sst/aws4fetch": ["aws4fetch@1.0.18", "", {}, "sha512-3Cf+YaUl07p24MoQ46rFwulAmiyCwH2+1zw1ZyPAX5OtJ34Hh185DwB8y/qRLb6cYYYtSFJ9pthyLc0MD4e8sQ=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], - "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], - "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], - "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=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], - "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=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "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=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "utif2/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "vitest/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], - "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=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "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=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "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=="], + "@aws-sdk/credential-providers/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], - "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@aws-sdk/credential-providers/@smithy/config-resolver/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="], - "xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], + "@aws-sdk/credential-providers/@smithy/config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + "@aws-sdk/credential-providers/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], - "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/credential-providers/@smithy/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "zod-to-ts/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], - "@actions/artifact/@actions/core/@actions/exec": ["@actions/exec@2.0.0", "", { "dependencies": { "@actions/io": "^2.0.0" } }, "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw=="], + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], - "@actions/core/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + "@aws-sdk/credential-providers/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], - "@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=="], + "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], - "@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=="], + "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "@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=="], + "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="], - "@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=="], + "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], - "@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=="], + "@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], - "@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="], + "@aws-sdk/nested-clients/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], - "@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="], + "@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], - "@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=="], + "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], - "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.5", "", {}, "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA=="], + "@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], - "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="], + "@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], - "@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-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], - "@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=="], + "@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], - "@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=="], + "@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], - "@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-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], - "@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=="], + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], - "@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=="], + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], - "@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=="], + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], - "@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=="], + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], - "@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=="], + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], - "@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=="], + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], "@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], @@ -4713,8 +5587,6 @@ "@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=="], @@ -4739,12 +5611,30 @@ "@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=="], + "@rollup/plugin-babel/@rollup/pluginutils/@types/estree": ["@types/estree@0.0.39", "", {}, "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="], + + "@rollup/plugin-babel/@rollup/pluginutils/estree-walker": ["estree-walker@1.0.1", "", {}, "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="], + + "@rollup/plugin-babel/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@rollup/plugin-replace/@rollup/pluginutils/@types/estree": ["@types/estree@0.0.39", "", {}, "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="], + + "@rollup/plugin-replace/@rollup/pluginutils/estree-walker": ["estree-walker@1.0.1", "", {}, "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="], + + "@rollup/plugin-replace/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@shuvcode/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=="], + "@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=="], + "@smithy/credential-provider-imds/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + "@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=="], @@ -4937,6 +5827,10 @@ "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "source-map/whatwg-url/tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="], + + "source-map/whatwg-url/webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "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=="], @@ -4953,6 +5847,8 @@ "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=="], + "workbox-build/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -4981,6 +5877,10 @@ "@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=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/core/@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/client-sso/@aws-sdk/core/@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/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=="], "@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=="], @@ -4989,6 +5889,128 @@ "@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=="], + "@aws-sdk/credential-provider-env/@aws-sdk/core/@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/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@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/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@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/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@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/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@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-process/@aws-sdk/core/@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/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@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/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@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/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@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/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/nested-clients/@aws-sdk/core/@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/token-providers/@aws-sdk/core/@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/token-providers/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.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-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], + "@jsx-email/cli/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "@jsx-email/cli/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -5063,7 +6085,7 @@ "@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=="], + "@shuvcode/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=="], @@ -5117,6 +6139,8 @@ "pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], + "source-map/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "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=="], @@ -5171,8 +6195,136 @@ "vitest/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + "@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=="], + "@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-providers/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], + "@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=="], @@ -5190,5 +6342,111 @@ "pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "tw-to-css/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/credential-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], } } diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000000..38764c56b57 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,34 @@ +# Docker Compose for running shuvcode +# +# Quick start: +# cd docker && docker compose up +# +# This builds everything from source and starts the server at http://localhost:4096 + +services: + shuvcode: + build: + context: .. + dockerfile: packages/opencode/Dockerfile + ports: + - "4096:4096" + volumes: + # Mount a workspace directory for the agent to work in + - ./workspace:/workspace + # Persist opencode data (sessions, config, etc.) + - shuvcode-data:/root/.opencode + environment: + # API keys - set these in your environment or .env file + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} + - OPENAI_API_KEY=${OPENAI_API_KEY:-} + - OPENCODE_API_KEY=${OPENCODE_API_KEY:-} + # Git user config - set these to use your own identity for commits + - GIT_AUTHOR_NAME=${GIT_AUTHOR_NAME:-shuvcode} + - GIT_AUTHOR_EMAIL=${GIT_AUTHOR_EMAIL:-shuvcode@localhost} + - GIT_COMMITTER_NAME=${GIT_COMMITTER_NAME:-shuvcode} + - GIT_COMMITTER_EMAIL=${GIT_COMMITTER_EMAIL:-shuvcode@localhost} + working_dir: /workspace + restart: unless-stopped + +volumes: + shuvcode-data: diff --git a/docs/ci-runner-discussion.md b/docs/ci-runner-discussion.md new file mode 100644 index 00000000000..8bda0760ecf --- /dev/null +++ b/docs/ci-runner-discussion.md @@ -0,0 +1,90 @@ +# CI Runner Configuration - December 2024 + +## Context + +The `shuvcode` repository is a public fork of `sst/opencode` that automatically syncs upstream releases, resolves merge conflicts (via OpenCode agent), and publishes to npm as `shuvcode`. + +## Current State + +### Upstream Sync Pipeline (Fully Automated) + +- Detects new upstream releases every 5 minutes +- Attempts automatic merge +- Creates GitHub issues for conflicts/validation failures +- Triggers OpenCode agent to resolve issues automatically +- Auto-closes issues when sync succeeds +- Publishes to npm via snapshot workflow + +### CI Runner Configuration + +**Decision: Use Blacksmith runners via Latitudes-Dev organization** + +All workflows now use hardcoded `blacksmith-4vcpu-ubuntu-2404` runners. + +| Runner Type | Status | Notes | +| ------------- | ------- | ---------------------------------- | +| Blacksmith | Active | Fast execution, no queue delays | +| GitHub-hosted | Removed | Was slow (20+ min queue times) | +| Self-hosted | Removed | Security concerns for public repos | + +### Migration Completed + +- [x] Repository transferred to `Latitudes-Dev/shuvcode` +- [x] Blacksmith enabled for the organization +- [x] All workflows updated to use Blacksmith runners +- [x] Self-hosted runner files removed (security) +- [x] Secrets configured in new organization + +## Workflows + +All workflows use `runs-on: blacksmith-4vcpu-ubuntu-2404`: + +| Workflow | Purpose | +| ------------------- | -------------------------------- | +| `format.yml` | Code formatting checks | +| `test.yml` | Run tests | +| `typecheck.yml` | TypeScript type checking | +| `snapshot.yml` | Publish `shuvcode` to npm | +| `upstream-sync.yml` | Sync from sst/opencode | +| `opencode.yml` | AI agent for conflict resolution | + +SST-only workflows (deploy, publish, extensions, stats, notifications) were removed. + +## Commands Reference + +### Check Workflow Status + +```bash +gh run list --repo Latitudes-Dev/shuvcode --limit 10 +gh run view --repo Latitudes-Dev/shuvcode +``` + +### Trigger Upstream Sync Manually + +```bash +gh workflow run upstream-sync.yml --repo Latitudes-Dev/shuvcode -f force_sync=true +``` + +### View Open Issues + +```bash +gh issue list --repo Latitudes-Dev/shuvcode --state open --label upstream-sync +``` + +## Related Files + +- `.github/workflows/upstream-sync.yml` - Main sync workflow +- `.github/workflows/opencode.yml` - OpenCode agent trigger +- `.github/workflows/snapshot.yml` - Publish workflow + +## Historical Notes + +### Why Not Self-Hosted Runners? + +Self-hosted runners on public repos pose security risks: anyone can fork the repo, create a PR with malicious workflow code, and execute arbitrary code on your server. PR-triggered workflows (format, test, typecheck) would be vulnerable. + +### Why Blacksmith? + +- Fast execution (no 20+ minute queue delays) +- Hosted service (no security concerns) +- Requires GitHub Organization (hence migration to Latitudes-Dev) diff --git a/github/action.yml b/github/action.yml index 8652bb8c151..b282b59a007 100644 --- a/github/action.yml +++ b/github/action.yml @@ -1,5 +1,5 @@ -name: "opencode GitHub Action" -description: "Run opencode in GitHub Actions workflows" +name: "shuvcode GitHub Action" +description: "Run shuvcode in GitHub Actions workflows" branding: icon: "code" color: "orange" @@ -27,7 +27,7 @@ inputs: default: "false" mentions: - description: "Comma-separated list of trigger phrases (case-insensitive). Defaults to '/opencode,/oc'" + description: "Comma-separated list of trigger phrases (case-insensitive). Defaults to '/shuvcode,/shuv,/opencode,/oc'" required: false oidc_base_url: @@ -37,33 +37,33 @@ inputs: runs: using: "composite" steps: - - name: Get opencode version + - name: Get shuvcode version id: version shell: bash run: | - VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4) + VERSION=$(curl -sf https://api.github.com/repos/Latitudes-Dev/shuvcode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4) echo "version=${VERSION:-latest}" >> $GITHUB_OUTPUT - - name: Cache opencode + - name: Cache shuvcode id: cache uses: actions/cache@v4 with: - path: ~/.opencode/bin - key: opencode-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }} + path: ~/.shuvcode/bin + key: shuvcode-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }} - - name: Install opencode + - name: Install shuvcode if: steps.cache.outputs.cache-hit != 'true' shell: bash - run: curl -fsSL https://opencode.ai/install | bash + run: curl -fsSL https://raw.githubusercontent.com/Latitudes-Dev/shuvcode/integration/install | bash - - name: Add opencode to PATH + - name: Add shuvcode to PATH shell: bash - run: echo "$HOME/.opencode/bin" >> $GITHUB_PATH + run: echo "$HOME/.shuvcode/bin" >> $GITHUB_PATH - - name: Run opencode + - name: Run shuvcode shell: bash - id: run_opencode - run: opencode github run + id: run_shuvcode + run: shuvcode github run env: MODEL: ${{ inputs.model }} AGENT: ${{ inputs.agent }} diff --git a/github/index.ts b/github/index.ts index 73378894cd3..31394b9fc98 100644 --- a/github/index.ts +++ b/github/index.ts @@ -231,7 +231,7 @@ function createOpencode() { const host = "127.0.0.1" const port = 4096 const url = `http://${host}:${port}` - const proc = spawn(`opencode`, [`serve`, `--hostname=${host}`, `--port=${port}`]) + const proc = spawn(`shuvcode`, [`serve`, `--hostname=${host}`, `--port=${port}`]) const client = createOpencodeClient({ baseUrl: url }) return { @@ -243,8 +243,8 @@ function createOpencode() { function assertPayloadKeyword() { 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`") + if (!body.match(/(?:^|\s)(?:\/shuvcode|\/shuv|\/opencode|\/oc)(?=$|\s)/)) { + throw new Error("Comments must mention `/shuvcode`, `/shuv`, `/opencode`, or `/oc`") } } @@ -362,7 +362,7 @@ function useIssueId() { } function useShareUrl() { - return isMock() ? "https://dev.opencode.ai" : "https://opencode.ai" + return isMock() ? "https://share.dev.shuv.ai" : "https://share.shuv.ai" } async function getAccessToken() { @@ -373,7 +373,7 @@ async function getAccessToken() { let response if (isMock()) { - response = await fetch("https://api.opencode.ai/exchange_github_app_token_with_pat", { + response = await fetch("https://api.shuv.ai/exchange_github_app_token_with_pat", { method: "POST", headers: { Authorization: `Bearer ${useEnvMock().mockToken}`, @@ -381,8 +381,8 @@ async function getAccessToken() { body: JSON.stringify({ owner: repo.owner, repo: repo.repo }), }) } else { - const oidcToken = await core.getIDToken("opencode-github-action") - response = await fetch("https://api.opencode.ai/exchange_github_app_token", { + const oidcToken = await core.getIDToken("shuvcode-github-action") + response = await fetch("https://api.shuv.ai/exchange_github_app_token", { method: "POST", headers: { Authorization: `Bearer ${oidcToken}`, @@ -417,19 +417,19 @@ async function getUserPrompt() { let prompt = (() => { const body = payload.comment.body.trim() - if (body === "/opencode" || body === "/oc") { + if (body === "/shuvcode" || body === "/shuv" || 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 (body.includes("/shuvcode") || body.includes("/shuv") || 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`") + throw new Error("Comments must mention `/shuvcode`, `/shuv`, `/opencode`, or `/oc`") })() // Handle images @@ -663,8 +663,8 @@ async function configureGit(appToken: string) { await $`git config --local --unset-all ${config}` await $`git config --local ${config} "AUTHORIZATION: basic ${newCredentials}"` - await $`git config --global user.name "opencode-agent[bot]"` - await $`git config --global user.email "opencode-agent[bot]@users.noreply.github.com"` + await $`git config --global user.name "shuvcode-agent[bot]"` + await $`git config --global user.email "shuvcode-agent[bot]@users.noreply.github.com"` } async function restoreGitConfig() { @@ -710,7 +710,7 @@ function generateBranchName(type: "issue" | "pr") { .replace(/\.\d{3}Z/, "") .split("T") .join("") - return `opencode/${type}${useIssueId()}-${timestamp}` + return `shuvcode/${type}${useIssueId()}-${timestamp}` } async function pushToNewBranch(summary: string, branch: string) { @@ -823,7 +823,7 @@ function footer(opts?: { image?: boolean }) { return `${titleAlt}\n` })() - const shareUrl = shareId ? `[opencode session](${useShareUrl()}/s/${shareId})  |  ` : "" + const shareUrl = shareId ? `[shuvcode session](${useShareUrl()}/s/${shareId})  |  ` : "" return `\n\n${image}${shareUrl}[github run](${useEnvRunUrl()})` } diff --git a/install b/install index 757694481c4..df0d41507c5 100755 --- a/install +++ b/install @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -euo pipefail -APP=opencode +APP=shuvcode MUTED='\033[0;2m' RED='\033[0;31m' @@ -16,19 +16,16 @@ Usage: install.sh [options] Options: -h, --help Display this help message -v, --version 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.) 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="" while [[ $# -gt 0 ]]; do case "$1" in @@ -45,15 +42,6 @@ while [[ $# -gt 0 ]]; do 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 @@ -65,128 +53,119 @@ while [[ $# -gt 0 ]]; do esac done -INSTALL_DIR=$HOME/.opencode/bin -mkdir -p "$INSTALL_DIR" +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 -# 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 - 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 - 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 - 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 - 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 - archive_ext=".zip" - if [ "$os" = "linux" ]; then - archive_ext=".tar.gz" +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 - is_musl=false - if [ "$os" = "linux" ]; then - if [ -f /etc/alpine-release ]; then - is_musl=true - 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 command -v ldd >/dev/null 2>&1; then - if ldd --version 2>&1 | grep -qi musl; then - is_musl=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 - 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 +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" = "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" +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 - if [ "$is_musl" = "true" ]; then - target="$target-musl" +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 - filename="$APP-$target$archive_ext" +INSTALL_DIR=$HOME/.shuvcode/bin +mkdir -p "$INSTALL_DIR" +if [ -z "$requested_version" ]; then + url="https://github.com/Latitudes-Dev/shuvcode/releases/latest/download/$filename" + specific_version=$(curl -s https://api.github.com/repos/Latitudes-Dev/shuvcode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') - 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 + if [[ $? -ne 0 || -z "$specific_version" ]]; then + echo -e "${RED}Failed to fetch version information${NC}" + exit 1 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 +else + # Strip leading 'v' if present + requested_version="${requested_version#v}" + url="https://github.com/Latitudes-Dev/shuvcode/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/Latitudes-Dev/shuvcode/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/Latitudes-Dev/shuvcode/releases${NC}" + exit 1 fi fi @@ -205,11 +184,11 @@ print_message() { } check_version() { - if command -v opencode >/dev/null 2>&1; then - opencode_path=$(which opencode) + if command -v shuvcode >/dev/null 2>&1; then + shuvcode_path=$(which shuvcode) ## Check the installed version - installed_version=$(opencode --version 2>/dev/null || echo "") + installed_version=$(shuvcode --version 2>/dev/null || echo "") if [[ "$installed_version" != "$specific_version" ]]; then print_message info "${MUTED}Installed version: ${NC}$installed_version." @@ -261,7 +240,7 @@ download_with_progress() { fi local tmp_dir=${TMPDIR:-/tmp} - local basename="${tmp_dir}/opencode_install_$$" + local basename="${tmp_dir}/shuvcode_install_$$" local tracefile="${basename}.trace" rm -f "$tracefile" @@ -273,7 +252,7 @@ download_with_progress() { trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN ( - curl --trace-ascii "$tracefile" -s -L -o "$output" "$url" + curl --trace-ascii "$tracefile" -s -f -L -o "$output" "$url" ) & local curl_pid=$! @@ -311,13 +290,13 @@ download_with_progress() { } download_and_install() { - print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version" - local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$" + print_message info "\n${MUTED}Installing ${NC}shuvcode ${MUTED}version: ${NC}$specific_version" + local tmp_dir="${TMPDIR:-/tmp}/shuvcode_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" + curl -f -# -L -o "$tmp_dir/$filename" "$url" fi if [ "$os" = "linux" ]; then @@ -326,23 +305,21 @@ download_and_install() { unzip -q "$tmp_dir/$filename" -d "$tmp_dir" fi - mv "$tmp_dir/opencode" "$INSTALL_DIR" - chmod 755 "${INSTALL_DIR}/opencode" + if [ "$os" = "windows" ]; then + mv "$tmp_dir/shuvcode.exe" "$INSTALL_DIR" + chmod 755 "${INSTALL_DIR}/shuvcode.exe" 2>/dev/null || true + # Convenience shim so `shuvcode` works in bash + printf '%s\n' '#!/usr/bin/env bash' 'exec "$(dirname "$0")/shuvcode.exe" "$@"' > "${INSTALL_DIR}/shuvcode" + chmod 755 "${INSTALL_DIR}/shuvcode" 2>/dev/null || true + else + mv "$tmp_dir/shuvcode" "$INSTALL_DIR" + chmod 755 "${INSTALL_DIR}/shuvcode" + fi rm -rf "$tmp_dir" } -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 +check_version +download_and_install add_to_path() { @@ -352,9 +329,9 @@ add_to_path() { if grep -Fxq "$command" "$config_file"; then print_message info "Command already exists in $config_file, skipping write." elif [[ -w $config_file ]]; then - echo -e "\n# opencode" >> "$config_file" + echo -e "\n# shuvcode" >> "$config_file" echo "$command" >> "$config_file" - print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file" + print_message info "${MUTED}Successfully added ${NC}shuvcode ${MUTED}to \$PATH in ${NC}$config_file" else print_message warning "Manually add the directory to $config_file (or similar):" print_message info " $command" @@ -430,17 +407,14 @@ if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then fi echo -e "" -echo -e "${MUTED}  ${NC} ▄ " -echo -e "${MUTED}█▀▀█ █▀▀█ █▀▀█ █▀▀▄ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█" -echo -e "${MUTED}█░░█ █░░█ █▀▀▀ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀" -echo -e "${MUTED}▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀" -echo -e "" +echo -e "${MUTED} ▄ ${NC} ▄ " +echo -e "${MUTED}█▀▀▀ █▀▀█ █ █ █ █ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█" +echo -e "${MUTED}▀▀▀█ █░░█ █░░█ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀" +echo -e "${MUTED}▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀" 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 "shuvcode ${MUTED}# Run command${NC}" echo -e "" +echo -e "${MUTED}A fork of opencode. For more info visit ${NC}https://shuv.ai" echo -e "" diff --git a/nix/bundle.ts b/nix/bundle.ts index effb1dff7cc..460865971dc 100644 --- a/nix/bundle.ts +++ b/nix/bundle.ts @@ -9,6 +9,7 @@ const parser = fs.realpathSync(path.join(dir, "node_modules/@opentui/core/parser const worker = "./src/cli/cmd/tui/worker.ts" const version = process.env.OPENCODE_VERSION ?? "local" const channel = process.env.OPENCODE_CHANNEL ?? "local" +const base = process.env.OPENCODE_BASE_VERSION ?? version fs.rmSync(path.join(dir, "dist"), { recursive: true, force: true }) @@ -22,6 +23,7 @@ const result = await Bun.build({ external: ["@opentui/core"], define: { OPENCODE_VERSION: `'${version}'`, + OPENCODE_BASE_VERSION: `'${base}'`, OPENCODE_CHANNEL: `'${channel}'`, // Leave undefined so runtime picks bundled/dist worker or fallback in code. OPENCODE_WORKER_PATH: "undefined", diff --git a/nix/scripts/bun-build.ts b/nix/scripts/bun-build.ts index a227081639d..4b54f49bdf2 100644 --- a/nix/scripts/bun-build.ts +++ b/nix/scripts/bun-build.ts @@ -4,6 +4,8 @@ import fs from "fs" const version = "@VERSION@" const pkg = path.join(process.cwd(), "packages/opencode") +const pkgjson = JSON.parse(fs.readFileSync(path.join(pkg, "package.json"), "utf8")) as { version?: string } +const base = pkgjson.version ?? version const parser = fs.realpathSync(path.join(pkg, "./node_modules/@opentui/core/parser.worker.js")) const worker = "./src/cli/cmd/tui/worker.ts" const target = process.env["BUN_COMPILE_TARGET"] @@ -54,6 +56,7 @@ const result = await Bun.build({ entrypoints: ["./src/index.ts", parser, worker], define: { OPENCODE_VERSION: `'@VERSION@'`, + OPENCODE_BASE_VERSION: `'${base}'`, OTUI_TREE_SITTER_WORKER_PATH: "/$bunfs/root/" + path.relative(pkg, parser).replace(/\\/g, "/"), OPENCODE_CHANNEL: "'latest'", }, diff --git a/package.json b/package.json index 66d2523652d..1b658c1f0ab 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", "typecheck": "bun turbo typecheck", "prepare": "husky", + "generate": "bun run --cwd packages/sdk/js build", "random": "echo 'Random script'", "hello": "echo 'Hello World!'", "test": "echo 'do not run tests from root' && exit 1" @@ -69,6 +70,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "3.933.0", + "@aws-sdk/credential-providers": "3.964.0", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", @@ -95,6 +97,7 @@ "@types/node": "catalog:" }, "patchedDependencies": { + "ghostty-opentui@1.3.7": "patches/ghostty-opentui@1.3.7.patch", "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch" } } diff --git a/packages/app/.gitignore b/packages/app/.gitignore index 4a20d55a70d..5440503b1a1 100644 --- a/packages/app/.gitignore +++ b/packages/app/.gitignore @@ -1 +1,2 @@ src/assets/theme.css +dev-dist/ diff --git a/packages/app/AGENTS.md b/packages/app/AGENTS.md index 98b681bca8a..0d9b7cd17ec 100644 --- a/packages/app/AGENTS.md +++ b/packages/app/AGENTS.md @@ -8,6 +8,27 @@ - Always prefer `createStore` over multiple `createSignal` calls +## Running Desktop in Development + +To run the desktop app in development mode, you need **two terminals**: + +1. **Terminal 1 - API Server** (from repo root): + + ```bash + bun run dev serve --port 4096 + ``` + +2. **Terminal 2 - Desktop App** (from packages/desktop): + ```bash + bun run dev + ``` + +The desktop dev server runs at http://localhost:3000 and connects to the API at port 4096. + +**Note**: The `--port 4096` flag is required because the server defaults to a random port (for multi-instance support in Tauri). The `.env.development` file sets `VITE_OPENCODE_SERVER_PORT=4096` so the desktop app knows where to connect. + +## Code Style + ## Tool Calling - ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. diff --git a/packages/app/index.html b/packages/app/index.html index 44fa3b989dc..833bc353615 100644 --- a/packages/app/index.html +++ b/packages/app/index.html @@ -1,53 +1,46 @@ - + - - OpenCode + + shuvcode - - + + + + + + + + + - - - - -
+
diff --git a/packages/app/package.json b/packages/app/package.json index 62eb1b055a5..03ad9e10e83 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.1.4", + "version": "1.1.4-1", "description": "", "type": "module", "exports": { @@ -26,6 +26,7 @@ "typescript": "catalog:", "vite": "catalog:", "vite-plugin-icons-spritesheet": "3.0.1", + "vite-plugin-pwa": "1.2.0", "vite-plugin-solid": "catalog:" }, "dependencies": { diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index a2f1aa4012c..4d9e88a910f 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -31,19 +31,28 @@ const Loading = () =>
localhost (same as upstream + shuv.ai) + if (location.hostname.includes("opencode.ai") || location.hostname.includes("shuv.ai")) + return "http://localhost:4096" + // 3. Desktop app (Tauri) with injected port + if (window.__SHUVCODE__?.port) return `http://127.0.0.1:${window.__SHUVCODE__.port}` + if (window.__OPENCODE__?.port) return `http://127.0.0.1:${window.__OPENCODE__.port}` + + // 4. Dev mode -> same-origin so Vite proxy handles LAN access + CORS + if (import.meta.env.DEV) return window.location.origin + + // 5. Default -> same origin (production web command) return window.location.origin }) @@ -60,7 +69,7 @@ export function App() { return ( - + }> diff --git a/packages/app/src/components/askquestion-wizard.tsx b/packages/app/src/components/askquestion-wizard.tsx new file mode 100644 index 00000000000..b98ff4eb54e --- /dev/null +++ b/packages/app/src/components/askquestion-wizard.tsx @@ -0,0 +1,565 @@ +import { createMemo, For, onMount, onCleanup, Show } from "solid-js" +import { createStore, produce } from "solid-js/store" +import { Button } from "@opencode-ai/ui/button" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { TextField } from "@opencode-ai/ui/text-field" + +// Types matching packages/opencode/src/askquestion/index.ts +export interface AskQuestionOption { + value: string + label: string + description?: string +} + +export interface AskQuestionQuestion { + id: string + label: string // Short tab label, e.g. "UI Framework" + question: string // Full question text + options: AskQuestionOption[] // 2-8 options + multiSelect?: boolean +} + +export interface AskQuestionAnswer { + questionId: string + values: string[] // Selected option value(s) + customText?: string // Custom text if user typed their own response +} + +export interface PendingAskQuestion { + callID: string + messageID: string + questions: AskQuestionQuestion[] +} + +export interface AskQuestionWizardProps { + questions: AskQuestionQuestion[] + onSubmit: (answers: AskQuestionAnswer[]) => void + onCancel: () => void +} + +interface QuestionState { + selectedOption: number + selectedValues: string[] + customText?: string +} + +export function AskQuestionWizard(props: AskQuestionWizardProps) { + // State for the wizard + const [store, setStore] = createStore({ + activeTab: 0, + questionStates: props.questions.map(() => ({ + selectedOption: 0, + selectedValues: [] as string[], + customText: undefined as string | undefined, + })) as QuestionState[], + isTypingCustom: false, + customInputValue: "", + }) + + let containerRef: HTMLDivElement | undefined + let inputRef: HTMLInputElement | undefined + + // Current question based on active tab + const currentQuestion = createMemo(() => props.questions[store.activeTab]) + const currentState = createMemo(() => store.questionStates[store.activeTab]) + + // Options including "Type something..." at the end + const optionsWithCustom = createMemo(() => [ + ...currentQuestion().options, + { value: "__custom__", label: "Type something...", description: "Enter your own response" }, + ]) + + // Check if all questions have at least one answer + const allAnswered = createMemo(() => + store.questionStates.every((state) => state.selectedValues.length > 0 || state.customText), + ) + + // Check if current question is answered + const currentAnswered = createMemo(() => { + const state = currentState() + return state.selectedValues.length > 0 || state.customText + }) + + function handleSubmit() { + if (!allAnswered()) return + const answers: AskQuestionAnswer[] = props.questions.map((q, i) => { + const state = store.questionStates[i] + return { + questionId: q.id, + values: state.selectedValues, + customText: state.customText, + } + }) + props.onSubmit(answers) + } + + function selectOption(optionValue: string) { + const question = currentQuestion() + setStore( + produce((s) => { + const state = s.questionStates[s.activeTab] + state.customText = undefined + + if (question.multiSelect) { + // Toggle for multi-select + const idx = state.selectedValues.indexOf(optionValue) + if (idx >= 0) { + state.selectedValues.splice(idx, 1) + } else { + state.selectedValues.push(optionValue) + } + } else { + // Select for single-select and auto-advance + state.selectedValues = [optionValue] + if (s.activeTab < props.questions.length - 1) { + s.activeTab++ + } + } + }), + ) + // Auto-submit if single-select on last question and all answered + if (!question.multiSelect) { + setTimeout(() => { + if (allAnswered()) { + handleSubmit() + } + }, 50) + } + } + + function navigateOption(direction: "up" | "down") { + const current = currentState().selectedOption + const max = optionsWithCustom().length - 1 + setStore( + produce((s) => { + if (direction === "up") { + s.questionStates[s.activeTab].selectedOption = current > 0 ? current - 1 : max + } else { + s.questionStates[s.activeTab].selectedOption = current < max ? current + 1 : 0 + } + }), + ) + } + + function navigateQuestion(direction: "left" | "right") { + if (direction === "right") { + if (store.activeTab < props.questions.length - 1) { + setStore("activeTab", store.activeTab + 1) + } else if (allAnswered()) { + handleSubmit() + } + } else { + if (store.activeTab > 0) { + setStore("activeTab", store.activeTab - 1) + } + } + } + + function openCustomInput() { + setStore("isTypingCustom", true) + setTimeout(() => inputRef?.focus(), 10) + } + + function submitCustomInput() { + const value = store.customInputValue.trim() + if (value) { + setStore( + produce((s) => { + s.questionStates[s.activeTab].customText = value + s.questionStates[s.activeTab].selectedValues = [] + }), + ) + } + setStore("isTypingCustom", false) + setStore("customInputValue", "") + // Auto-advance to next question or submit + if (store.activeTab < props.questions.length - 1) { + setStore("activeTab", store.activeTab + 1) + } else if (allAnswered()) { + handleSubmit() + } + } + + function handleKeyDown(evt: KeyboardEvent) { + // Allow the event to be handled when inside our component + if (store.isTypingCustom) { + // In custom input mode + if (evt.key === "Escape") { + evt.preventDefault() + evt.stopPropagation() + setStore("isTypingCustom", false) + setStore("customInputValue", "") + return + } + if (evt.key === "Enter" && !evt.shiftKey) { + evt.preventDefault() + evt.stopPropagation() + submitCustomInput() + return + } + // Let other keys through for typing + return + } + + // Tab/arrow navigation between questions + if (evt.key === "Tab" && !evt.shiftKey) { + evt.preventDefault() + evt.stopPropagation() + navigateQuestion("right") + return + } + if (evt.key === "Tab" && evt.shiftKey) { + evt.preventDefault() + evt.stopPropagation() + navigateQuestion("left") + return + } + if (evt.key === "ArrowRight") { + evt.preventDefault() + evt.stopPropagation() + navigateQuestion("right") + return + } + if (evt.key === "ArrowLeft") { + evt.preventDefault() + evt.stopPropagation() + navigateQuestion("left") + return + } + + // Up/down navigation within options + if (evt.key === "ArrowUp" || (evt.ctrlKey && evt.key === "p")) { + evt.preventDefault() + evt.stopPropagation() + navigateOption("up") + return + } + if (evt.key === "ArrowDown" || (evt.ctrlKey && evt.key === "n")) { + evt.preventDefault() + evt.stopPropagation() + navigateOption("down") + return + } + + // Space to toggle selection (especially useful for multi-select) + if (evt.key === " ") { + evt.preventDefault() + evt.stopPropagation() + const selectedIdx = currentState().selectedOption + const option = optionsWithCustom()[selectedIdx] + + if (option.value === "__custom__") { + openCustomInput() + return + } + + selectOption(option.value) + return + } + + // Enter to select option (single-select) or confirm and advance (multi-select) + if (evt.key === "Enter" && !evt.ctrlKey && !evt.metaKey) { + evt.preventDefault() + evt.stopPropagation() + const selectedIdx = currentState().selectedOption + const option = optionsWithCustom()[selectedIdx] + + if (option.value === "__custom__") { + openCustomInput() + return + } + + const question = currentQuestion() + if (question.multiSelect) { + // For multi-select: Enter confirms current selections and advances + if (currentAnswered()) { + navigateQuestion("right") + return + } + // If nothing selected yet, toggle the current option + selectOption(option.value) + return + } + + // Single-select: select and advance + selectOption(option.value) + return + } + + // Number keys for quick selection (1-8) + if (evt.key >= "1" && evt.key <= "8" && !evt.ctrlKey && !evt.metaKey) { + evt.preventDefault() + evt.stopPropagation() + const idx = parseInt(evt.key) - 1 + if (idx < currentQuestion().options.length) { + const option = currentQuestion().options[idx] + selectOption(option.value) + } + return + } + + // Escape to cancel + if (evt.key === "Escape") { + evt.preventDefault() + evt.stopPropagation() + props.onCancel() + return + } + + // Ctrl+Enter to submit + if ((evt.ctrlKey || evt.metaKey) && evt.key === "Enter") { + evt.preventDefault() + evt.stopPropagation() + if (allAnswered()) { + handleSubmit() + } + return + } + } + + onMount(() => { + // Focus container to capture keyboard events + containerRef?.focus() + document.addEventListener("keydown", handleKeyDown, true) + }) + + onCleanup(() => { + document.removeEventListener("keydown", handleKeyDown, true) + }) + + return ( +
+
+
Answer the questions
+ +
+ {/* Tab bar */} +
+ + + {(question, index) => { + const isActive = createMemo(() => store.activeTab === index()) + const isAnswered = createMemo(() => { + const state = store.questionStates[index()] + return state.selectedValues.length > 0 || !!state.customText + }) + return ( + + ) + }} + + + + + +
+ + {/* Current question */} +
+

{currentQuestion().question}

+ +

(select multiple, press Enter to confirm)

+
+
+ + {/* Options */} +
+ + {(option, index) => { + const isSelected = createMemo(() => currentState().selectedOption === index()) + const isChosen = createMemo(() => { + if (option.value === "__custom__") { + return !!currentState().customText + } + return currentState().selectedValues.includes(option.value) + }) + const isCustomOption = option.value === "__custom__" + + return ( + + ) + }} + +
+ + {/* Custom input (when active) */} + +
+ setStore("customInputValue", value)} + onKeyDown={(e: KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault() + submitCustomInput() + } else if (e.key === "Escape") { + e.preventDefault() + setStore("isTypingCustom", false) + setStore("customInputValue", "") + } + }} + /> +
+ + +
+
+
+ + {/* Instructions - hidden on mobile */} + + + {/* Action buttons - desktop */} + + + {/* Sticky footer - mobile only */} +
+ + + + +
+
+ ) +} diff --git a/packages/app/src/components/dialog-create-project.tsx b/packages/app/src/components/dialog-create-project.tsx new file mode 100644 index 00000000000..66c5500d2d0 --- /dev/null +++ b/packages/app/src/components/dialog-create-project.tsx @@ -0,0 +1,673 @@ +import { Component, createSignal, createMemo, Show } from "solid-js" +import { createStore } from "solid-js/store" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useGlobalSDK } from "@/context/global-sdk" +import { useLayout } from "@/context/layout" +import { Dialog } from "@opencode-ai/ui/dialog" +import { TextField } from "@opencode-ai/ui/text-field" +import { Switch } from "@opencode-ai/ui/switch" +import { Button } from "@opencode-ai/ui/button" +import { Spinner } from "@opencode-ai/ui/spinner" +import { showToast } from "@opencode-ai/ui/toast" +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 { useGlobalSync } from "@/context/global-sync" +import { List } from "@opencode-ai/ui/list" + +interface DirectoryInfo { + path: string + name: string + isGitRepo: boolean + isExistingProject: boolean +} + +// Helper to validate project name (no path separators, no traversal) +function validateProjectName(name: string): string | undefined { + if (!name.trim()) return "Project name is required" + if (name.includes("/") || name.includes("\\")) return "Project name cannot contain path separators" + if (name === "." || name === "..") return "Invalid project name" + if (name.includes("..")) return "Project name cannot contain path traversal" + return undefined +} + +// Helper to derive folder name from repo URL +function deriveFolderNameFromRepo(repoUrl: string): string { + if (!repoUrl.trim()) return "" + // Remove trailing slashes, .git suffix, and get the last path segment + const cleaned = repoUrl.trim().replace(/\/+$/, "").replace(/\.git$/, "") + const parts = cleaned.split("/") + const lastPart = parts[parts.length - 1] || "" + // Remove any remaining path separators from the derived name + return lastPart.replace(/[/\\]/g, "") +} + +// Helper to compute resolved path +function computeResolvedPath(parentDir: string, projectName: string): string { + if (!parentDir || !projectName.trim()) return "" + // Normalize parent dir (remove trailing slash) + const normalizedParent = parentDir.replace(/\/+$/, "") + return `${normalizedParent}/${projectName.trim()}` +} + +export const DialogCreateProject: Component = () => { + const dialog = useDialog() + const globalSDK = useGlobalSDK() + const layout = useLayout() + const navigate = useNavigate() + const platform = usePlatform() + const sync = useGlobalSync() + + const [activeTab, setActiveTab] = createSignal<"existing" | "create" | "clone">("existing") + const [selectedDir, setSelectedDir] = createSignal(null) + + const [store, setStore] = createStore({ + // Common + error: undefined as string | undefined, + loading: false, + // Create New flow + createParentDir: "", + createProjectName: "", + // Clone flow + cloneRepoUrl: "", + cloneParentDir: "", + cloneProjectName: "", // Optional, derived from repo if empty + cloneDegit: false, + }) + + const homedir = createMemo(() => sync.data.path.home || "~") + + // Computed resolved paths + const createResolvedPath = createMemo(() => computeResolvedPath(store.createParentDir, store.createProjectName)) + + const cloneDerivedName = createMemo(() => { + if (store.cloneProjectName.trim()) return store.cloneProjectName.trim() + return deriveFolderNameFromRepo(store.cloneRepoUrl) + }) + + const cloneResolvedPath = createMemo(() => computeResolvedPath(store.cloneParentDir, cloneDerivedName())) + + // Validation for Create New + const createNameError = createMemo(() => validateProjectName(store.createProjectName)) + const createPathError = createMemo(() => { + const path = createResolvedPath() + if (!path) return undefined + if (!path.startsWith("/") && !path.startsWith("~")) return "Path must be absolute" + return undefined + }) + + // Validation for Clone + const cloneRepoError = createMemo(() => { + if (!store.cloneRepoUrl.trim()) return "Repository URL is required" + return undefined + }) + const cloneNameError = createMemo(() => { + const name = cloneDerivedName() + if (!name) return "Project name is required (enter manually or provide valid repo URL)" + return validateProjectName(name) + }) + const clonePathError = createMemo(() => { + const path = cloneResolvedPath() + if (!path) return undefined + if (!path.startsWith("/") && !path.startsWith("~")) return "Path must be absolute" + return undefined + }) + + // Fetch directories for browsing - returns a function for the List component + async function fetchDirectories(query: string): Promise { + const result = await globalSDK.client.project.browse({ + query: query || undefined, + limit: 50, + }) + if (result.error) return [] + return (result.data as DirectoryInfo[]) || [] + } + + function openProject(directory: string) { + layout.projects.open(directory) + navigate(`/${base64Encode(directory)}`) + } + + async function handleCreateSubmit(e: SubmitEvent) { + e.preventDefault() + + // Validate + const nameError = createNameError() + if (nameError) { + setStore("error", nameError) + return + } + if (!store.createParentDir) { + setStore("error", "Parent directory is required") + return + } + const pathError = createPathError() + if (pathError) { + setStore("error", pathError) + return + } + + const resolvedPath = createResolvedPath() + if (!resolvedPath) { + setStore("error", "Could not resolve project path") + return + } + + setStore("error", undefined) + setStore("loading", true) + + try { + const result = await globalSDK.client.project.create({ + path: resolvedPath, + name: store.createProjectName.trim(), + }) + + if (result.error) { + const errorMessage = (result.error as { message?: string }).message || "Failed to create project" + setStore("error", errorMessage) + setStore("loading", false) + return + } + + const { project, created } = result.data! + dialog.close() + openProject(project.worktree) + + showToast({ + variant: "success", + icon: "circle-check", + title: created ? "Project created" : "Project added", + description: created + ? `Created project at ${project.worktree.replace(homedir(), "~")}` + : `Added ${project.worktree.replace(homedir(), "~")}`, + }) + } catch (e: unknown) { + const errorMessage = e instanceof Error ? e.message : "Failed to create project" + setStore("error", errorMessage) + setStore("loading", false) + } + } + + async function handleCloneSubmit(e: SubmitEvent) { + e.preventDefault() + + // Validate + const repoError = cloneRepoError() + if (repoError) { + setStore("error", repoError) + return + } + if (!store.cloneParentDir) { + setStore("error", "Parent directory is required") + return + } + const nameError = cloneNameError() + if (nameError) { + setStore("error", nameError) + return + } + const pathError = clonePathError() + if (pathError) { + setStore("error", pathError) + return + } + + const resolvedPath = cloneResolvedPath() + if (!resolvedPath) { + setStore("error", "Could not resolve project path") + return + } + + setStore("error", undefined) + setStore("loading", true) + + try { + const result = await globalSDK.client.project.create({ + path: resolvedPath, + repo: store.cloneRepoUrl.trim(), + degit: store.cloneDegit, + name: cloneDerivedName(), + }) + + if (result.error) { + const errorMessage = (result.error as { message?: string }).message || "Failed to clone repository" + setStore("error", errorMessage) + setStore("loading", false) + return + } + + const { project, created } = result.data! + dialog.close() + openProject(project.worktree) + + showToast({ + variant: "success", + icon: "circle-check", + title: created ? "Repository cloned" : "Project added", + description: created + ? `Cloned to ${project.worktree.replace(homedir(), "~")}` + : `Added ${project.worktree.replace(homedir(), "~")}`, + }) + } catch (e: unknown) { + const errorMessage = e instanceof Error ? e.message : "Failed to clone repository" + setStore("error", errorMessage) + setStore("loading", false) + } + } + + async function handleAddExisting(dir?: DirectoryInfo | null) { + const directory = dir ?? selectedDir() + if (!directory) return + + setStore("loading", true) + setStore("error", undefined) + + try { + // Use create endpoint - it handles existing directories gracefully + const result = await globalSDK.client.project.create({ path: directory.path }) + + if (result.error) { + const errorMessage = (result.error as { message?: string }).message || "Failed to add project" + setStore("error", errorMessage) + setStore("loading", false) + return + } + + const { project } = result.data! + dialog.close() + openProject(project.worktree) + + showToast({ + variant: "success", + icon: "circle-check", + title: "Project added", + description: `Added ${project.worktree.replace(homedir(), "~")}`, + }) + } catch (e: unknown) { + const errorMessage = e instanceof Error ? e.message : "Failed to add project" + setStore("error", errorMessage) + setStore("loading", false) + } + } + + async function handleBrowseExisting() { + const result = await platform.openDirectoryPickerDialog?.({ + title: "Select folder to add as project", + multiple: false, + }) + if (result && typeof result === "string") { + // Directly add the selected directory + setStore("loading", true) + try { + const createResult = await globalSDK.client.project.create({ path: result }) + if (createResult.error) { + const errorMessage = (createResult.error as { message?: string }).message || "Failed to add project" + setStore("error", errorMessage) + setStore("loading", false) + return + } + const { project } = createResult.data! + dialog.close() + openProject(project.worktree) + showToast({ + variant: "success", + icon: "circle-check", + title: "Project added", + description: `Added ${project.worktree.replace(homedir(), "~")}`, + }) + } catch (e: unknown) { + const errorMessage = e instanceof Error ? e.message : "Failed to add project" + setStore("error", errorMessage) + setStore("loading", false) + } + } + } + + async function handleBrowseCreateParent() { + const result = await platform.openDirectoryPickerDialog?.({ + title: "Select parent directory for new project", + multiple: false, + }) + if (result && typeof result === "string") { + setStore("createParentDir", result) + } + } + + async function handleBrowseCloneParent() { + const result = await platform.openDirectoryPickerDialog?.({ + title: "Select parent directory for cloned repository", + multiple: false, + }) + if (result && typeof result === "string") { + setStore("cloneParentDir", result) + } + } + + function handleSelect(dir: DirectoryInfo | undefined) { + if (!dir) return + if (dir.isExistingProject) { + dialog.close() + openProject(dir.path) + return + } + setSelectedDir(dir) + // Immediately add the project on selection + handleAddExisting(dir) + } + + return ( + +
+ {/* Tab switcher */} +
+ + + +
+ + {/* Add Existing tab content */} + +
+
+ Search for an existing folder to add as a project, or browse your filesystem. +
+ + {/* Directory list with search */} + + class="flex-1 min-h-0 [&_[data-slot=list-item]]:h-auto [&_[data-slot=list-item]]:py-1" + items={fetchDirectories} + key={(dir) => dir.path} + filterKeys={["name", "path"]} + current={selectedDir() ?? undefined} + onSelect={handleSelect} + search={{ placeholder: "Search folders...", autofocus: true }} + emptyMessage="No folders found" + > + {(dir) => ( +
+ + {dir.path.replace(homedir(), "~")} + + git + + + open + +
+ )} + + + {/* Browse button */} + + + + + +
{store.error}
+
+ + +
+ +
+
+
+
+ + {/* Create New tab content */} + +
+
+ Select a parent directory and enter a name for your new project. A new folder will be created and + initialized as a git repository. +
+ + {/* Parent directory browser */} +
+ + +
+ + + {store.createParentDir.replace(homedir(), "~")} + + +
+
+ + + class="flex-1 min-h-0 max-h-40 [&_[data-slot=list-item]]:h-auto [&_[data-slot=list-item]]:py-1" + items={fetchDirectories} + key={(dir) => dir.path} + filterKeys={["name", "path"]} + onSelect={(dir) => dir && setStore("createParentDir", dir.path)} + search={{ placeholder: "Search folders...", autofocus: activeTab() === "create" }} + emptyMessage="No folders found" + > + {(dir) => ( +
+ + {dir.path.replace(homedir(), "~")} +
+ )} + + + + +
+
+ + {/* Project name */} + setStore("createProjectName", value)} + validationState={createNameError() ? "invalid" : undefined} + error={createNameError()} + /> + + {/* Resolved path preview */} + +
+ +
+ {createResolvedPath().replace(homedir(), "~")} +
+
+
+ + +
{store.error}
+
+ +
+ + +
+ +
+ + {/* Git Clone tab content */} + +
+
+ Clone a git repository into a new project folder. +
+ + {/* Repository URL */} + setStore("cloneRepoUrl", value)} + /> + + {/* Parent directory browser */} +
+ + +
+ + + {store.cloneParentDir.replace(homedir(), "~")} + + +
+
+ + + class="flex-1 min-h-0 max-h-40 [&_[data-slot=list-item]]:h-auto [&_[data-slot=list-item]]:py-1" + items={fetchDirectories} + key={(dir) => dir.path} + filterKeys={["name", "path"]} + onSelect={(dir) => dir && setStore("cloneParentDir", dir.path)} + search={{ placeholder: "Search folders..." }} + emptyMessage="No folders found" + > + {(dir) => ( +
+ + {dir.path.replace(homedir(), "~")} +
+ )} + + + + +
+
+ + {/* Project name (optional, derived from repo) */} + setStore("cloneProjectName", value)} + validationState={store.cloneProjectName.trim() && cloneNameError() ? "invalid" : undefined} + error={store.cloneProjectName.trim() ? cloneNameError() : undefined} + /> + + {/* Resolved path preview */} + +
+ +
+ {cloneResolvedPath().replace(homedir(), "~")} +
+
+
+ + {/* Degit toggle */} +
+ setStore("cloneDegit", checked)}> + Degit (remove .git history after cloning) + +
+ + +
{store.error}
+
+ +
+ + +
+ +
+
+
+ ) +} diff --git a/packages/app/src/components/dialog-select-directory.tsx b/packages/app/src/components/dialog-select-directory.tsx deleted file mode 100644 index bf4a1f9edd4..00000000000 --- a/packages/app/src/components/dialog-select-directory.tsx +++ /dev/null @@ -1,114 +0,0 @@ -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" - -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 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-provider.tsx b/packages/app/src/components/dialog-select-provider.tsx index 5bbde5d41a2..76a3dd661ee 100644 --- a/packages/app/src/components/dialog-select-provider.tsx +++ b/packages/app/src/components/dialog-select-provider.tsx @@ -37,14 +37,14 @@ export const DialogSelectProvider: Component = () => { }} > {(i) => ( -
+
- {i.name} + {i.name} Recommended -
Connect with Claude Pro/Max or API key
+
Connect with Claude Pro/Max or API key
)} diff --git a/packages/app/src/components/dialog-session-rename-global.tsx b/packages/app/src/components/dialog-session-rename-global.tsx new file mode 100644 index 00000000000..7df5a9f6b29 --- /dev/null +++ b/packages/app/src/components/dialog-session-rename-global.tsx @@ -0,0 +1,67 @@ +import { Component, createEffect } from "solid-js" +import { createStore } from "solid-js/store" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { TextField } from "@opencode-ai/ui/text-field" +import { Button } from "@opencode-ai/ui/button" +import { useGlobalSDK } from "@/context/global-sdk" +import type { Session } from "@opencode-ai/sdk/v2/client" + +interface DialogSessionRenameGlobalProps { + session: Session +} + +export const DialogSessionRenameGlobal: Component = (props) => { + const dialog = useDialog() + const globalSDK = useGlobalSDK() + + const [store, setStore] = createStore({ + value: props.session.title ?? "", + error: undefined as string | undefined, + }) + + // Prefill with session title on mount + createEffect(() => { + if (props.session.title && !store.value) { + setStore("value", props.session.title) + } + }) + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + const trimmed = store.value.trim() + + if (!trimmed) { + setStore("error", "Session name is required") + return + } + + await globalSDK.client.session.update({ + directory: props.session.directory, + sessionID: props.session.id, + title: trimmed, + }) + dialog.close() + } + + return ( + +
+ setStore({ value, error: undefined })} + validationState={store.error ? "invalid" : undefined} + error={store.error} + /> +
+ + +
+ +
+ ) +} diff --git a/packages/app/src/components/dialog-session-rename.tsx b/packages/app/src/components/dialog-session-rename.tsx new file mode 100644 index 00000000000..0cdeea18bbb --- /dev/null +++ b/packages/app/src/components/dialog-session-rename.tsx @@ -0,0 +1,69 @@ +import { Component, createMemo, createEffect } from "solid-js" +import { createStore } from "solid-js/store" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { Dialog } from "@opencode-ai/ui/dialog" +import { TextField } from "@opencode-ai/ui/text-field" +import { Button } from "@opencode-ai/ui/button" +import { useSDK } from "@/context/sdk" +import { useSync } from "@/context/sync" + +interface DialogSessionRenameProps { + sessionID: string +} + +export const DialogSessionRename: Component = (props) => { + const dialog = useDialog() + const sdk = useSDK() + const sync = useSync() + + const session = createMemo(() => sync.session.get(props.sessionID)) + const [store, setStore] = createStore({ + value: "", + error: undefined as string | undefined, + }) + + // Prefill the input when session data becomes available + createEffect(() => { + const s = session() + if (s?.title && !store.value) { + setStore("value", s.title) + } + }) + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + const trimmed = store.value.trim() + + if (!trimmed) { + setStore("error", "Session name is required") + return + } + + await sdk.client.session.update({ + sessionID: props.sessionID, + title: trimmed, + }) + dialog.close() + } + + return ( + +
+ setStore({ value, error: undefined })} + validationState={store.error ? "invalid" : undefined} + error={store.error} + /> +
+ + +
+ +
+ ) +} diff --git a/packages/app/src/components/font-picker.tsx b/packages/app/src/components/font-picker.tsx new file mode 100644 index 00000000000..91f2243bb5a --- /dev/null +++ b/packages/app/src/components/font-picker.tsx @@ -0,0 +1,103 @@ +import { createMemo, createSignal, onMount, Show } from "solid-js" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { FONTS, getFontById, type FontDefinition } from "@/fonts/font-definitions" +import { useLayout } from "@/context/layout" +import { applyFontWithLoad, ensureFontLoaded, applyFont } from "@/fonts/apply-font" + +function DialogSelectFont(props: { originalFont: string }) { + const layout = useLayout() + const dialog = useDialog() + const [previewFont, setPreviewFont] = createSignal(props.originalFont) + const currentFont = createMemo(() => getFontById(previewFont()) ?? FONTS[0]) + + async function handleSelect(font: FontDefinition | undefined) { + if (!font) return + + const loaded = await ensureFontLoaded(font) + if (!loaded) return + + layout.font.set(font.id) + applyFont(font.id) + dialog.close() + } + + async function handleActiveChange(font: FontDefinition | undefined) { + if (!font) return + + const loaded = await ensureFontLoaded(font) + if (!loaded) return + + setPreviewFont(font.id) + applyFont(font.id) + } + + return ( + + f.id} + items={() => [...FONTS]} + current={currentFont()} + filterKeys={["name", "family"]} + onSelect={handleSelect} + onActiveChange={handleActiveChange} + > + {(font: FontDefinition) => ( +
+ {font.name} +
+ )} +
+
+ ) +} + +export function FontPicker(props: { class?: string; mobile?: boolean }) { + const layout = useLayout() + const dialog = useDialog() + const currentFont = createMemo(() => getFontById(layout.font.current()) ?? FONTS[0]) + + onMount(() => applyFontWithLoad(currentFont())) + + function openDialog() { + const originalFont = currentFont().id + dialog.show( + () => , + () => applyFont(originalFont), + ) + } + + return ( + + + + } + > + + + ) +} diff --git a/packages/app/src/components/header.tsx b/packages/app/src/components/header.tsx new file mode 100644 index 00000000000..55fd5ff5ca3 --- /dev/null +++ b/packages/app/src/components/header.tsx @@ -0,0 +1,235 @@ +import { useGlobalSync } from "@/context/global-sync" +import { useGlobalSDK } from "@/context/global-sdk" +import { useLayout } from "@/context/layout" +import { Session } from "@opencode-ai/sdk/v2/client" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { AsciiLogo, AsciiMark } from "@opencode-ai/ui/logo" +import { Popover } from "@opencode-ai/ui/popover" +import { Select } from "@opencode-ai/ui/select" +import { TextField } from "@opencode-ai/ui/text-field" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { base64Decode } from "@opencode-ai/util/encode" +import { useCommand } from "@/context/command" +import { getFilename } from "@opencode-ai/util/path" +import { A, useParams } from "@solidjs/router" +import { createMemo, createResource, Show } from "solid-js" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { iife } from "@opencode-ai/util/iife" +import { ThemePicker } from "@/components/theme-picker" +import { FontPicker } from "@/components/font-picker" + +export function Header(props: { + navigateToProject: (directory: string) => void + navigateToSession: (session: Session | undefined) => void + onMobileMenuToggle?: () => void +}) { + const globalSync = useGlobalSync() + const globalSDK = useGlobalSDK() + const layout = useLayout() + const params = useParams() + const command = useCommand() + + return ( +
+ + + }> + + + +
+ 0 && params.dir} + fallback={ + + } + > + {(directory) => { + const currentDirectory = createMemo(() => base64Decode(directory())) + const store = createMemo(() => globalSync.child(currentDirectory())[0]) + const sessions = createMemo(() => (store().session ?? []).filter((s) => !s.parentID)) + const currentSession = createMemo(() => sessions().find((s) => s.id === params.id)) + const shareEnabled = createMemo(() => store().config.share !== "disabled") + return ( + <> +
+
+ + + ) +} diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index fc4a3d1e648..1f3068aa7c3 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -422,7 +422,13 @@ export const PromptInput: Component = (props) => { type: "custom" as const, })) - return [...custom, ...builtin] + const all = [...custom, ...builtin] + const seen = new Set() + return all.filter((cmd) => { + if (seen.has(cmd.trigger)) return false + seen.add(cmd.trigger) + return true + }) }) const handleSlashSelect = (cmd: SlashCommand | undefined) => { @@ -448,7 +454,12 @@ export const PromptInput: Component = (props) => { editorRef.innerHTML = "" prompt.set([{ type: "text", content: "", start: 0, end: 0 }], 0) - command.trigger(cmd.id, "slash") + try { + command.trigger(cmd.id, "slash") + } catch (error) { + // Defensive: handle stale command handlers gracefully + console.error("Failed to execute slash command:", cmd.id, error) + } } const { @@ -1207,6 +1218,9 @@ export const PromptInput: Component = (props) => { filename: attachment.filename, })) + // Blur the editor to dismiss mobile keyboard after submission + editorRef.blur() + const messageID = Identifier.ascending("message") const textPart = { id: Identifier.ascending("part"), @@ -1315,7 +1329,10 @@ export const PromptInput: Component = (props) => { "w-full flex items-center gap-x-2 rounded-md px-2 py-0.5": true, "bg-surface-raised-base-hover": atActive() === atKey(item), }} - onClick={() => handleAtSelect(item)} + onMouseDown={(e) => { + e.preventDefault() + handleAtSelect(item) + }} > = (props) => { "w-full flex items-center justify-between gap-4 rounded-md px-2 py-1": true, "bg-surface-raised-base-hover": slashActive() === cmd.id, }} - onClick={() => handleSlashSelect(cmd)} + onMouseDown={(e) => { + e.preventDefault() + handleSlashSelect(cmd) + }} >
/{cmd.trigger} @@ -1655,7 +1675,7 @@ export const PromptInput: Component = (props) => { disabled={!prompt.dirty() && !working()} icon={working() ? "stop" : "arrow-up"} variant="primary" - class="h-6 w-4.5" + class="size-8 rounded-md" />
diff --git a/packages/app/src/components/pull-to-refresh.tsx b/packages/app/src/components/pull-to-refresh.tsx new file mode 100644 index 00000000000..6f39cf708e5 --- /dev/null +++ b/packages/app/src/components/pull-to-refresh.tsx @@ -0,0 +1,159 @@ +import { createSignal, onCleanup, onMount, ParentProps, Show } from "solid-js" +import { Spinner } from "@opencode-ai/ui/spinner" + +const PULL_THRESHOLD = 80 +const RESISTANCE = 2.5 + +export interface PullToRefreshProps extends ParentProps { + enabled?: boolean | (() => boolean) +} + +export function PullToRefresh(props: PullToRefreshProps) { + let containerRef: HTMLDivElement | undefined + const [pullDistance, setPullDistance] = createSignal(0) + const [isRefreshing, setIsRefreshing] = createSignal(false) + const [startY, setStartY] = createSignal(0) + const [isPulling, setIsPulling] = createSignal(false) + + const isEnabled = () => { + if (typeof props.enabled === "function") return props.enabled() + return props.enabled ?? true + } + + const canPull = () => { + if (!containerRef) return false + // Only allow pull when scrolled to top + const scrollTop = containerRef.scrollTop + return scrollTop <= 0 + } + + const handleTouchStart = (e: TouchEvent) => { + if (!isEnabled()) return + if (isRefreshing()) return + if (!canPull()) return + + const touch = e.touches[0] + setStartY(touch.clientY) + setIsPulling(true) + } + + const handleTouchMove = (e: TouchEvent) => { + if (!isEnabled()) return + if (!isPulling() || isRefreshing()) return + + const touch = e.touches[0] + const deltaY = touch.clientY - startY() + + if (deltaY > 0 && canPull()) { + // Apply resistance to make pull feel natural + const distance = Math.min(deltaY / RESISTANCE, PULL_THRESHOLD * 1.5) + setPullDistance(distance) + + // Prevent default scrolling while pulling + if (distance > 0) { + e.preventDefault() + } + } else { + setPullDistance(0) + } + } + + const handleTouchEnd = async () => { + if (!isEnabled()) return + if (!isPulling()) return + setIsPulling(false) + + if (pullDistance() >= PULL_THRESHOLD && !isRefreshing()) { + setIsRefreshing(true) + setPullDistance(PULL_THRESHOLD / 2) // Show spinner at a nice position + + // Perform refresh + try { + await new Promise((resolve) => setTimeout(resolve, 300)) + window.location.reload() + } catch { + setIsRefreshing(false) + setPullDistance(0) + } + } else { + setPullDistance(0) + } + } + + onMount(() => { + if (!containerRef) return + + containerRef.addEventListener("touchstart", handleTouchStart, { passive: true }) + containerRef.addEventListener("touchmove", handleTouchMove, { passive: false }) + containerRef.addEventListener("touchend", handleTouchEnd, { passive: true }) + + onCleanup(() => { + if (!containerRef) return + containerRef.removeEventListener("touchstart", handleTouchStart) + containerRef.removeEventListener("touchmove", handleTouchMove) + containerRef.removeEventListener("touchend", handleTouchEnd) + }) + }) + + const progress = () => Math.min(pullDistance() / PULL_THRESHOLD, 1) + const shouldShowIndicator = () => pullDistance() > 10 || isRefreshing() + + return ( +
+ {/* Pull indicator */} + +
+
+ + + + + +
+ } + > + + +
+
+
+ + {/* Content with pull transform */} +
0 ? `translateY(${pullDistance()}px)` : undefined, + transition: isPulling() ? "none" : "transform 0.2s ease-out", + }} + > + {props.children} +
+
+ ) +} diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 4958ad2c353..2d1f509a09d 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -56,7 +56,7 @@ export function SessionHeader() { } return ( -
+
+
+ + v{platform.version} + + + + + + +
+
{props.children}
+
+ ) +} diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index 8b25f740b36..283aad255fe 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -1,9 +1,10 @@ import type { Ghostty, Terminal as Term, FitAddon } from "ghostty-web" -import { ComponentProps, createEffect, createSignal, onCleanup, onMount, splitProps } from "solid-js" +import { ComponentProps, createEffect, createSignal, onCleanup, onMount, Show, splitProps } from "solid-js" import { useSDK } from "@/context/sdk" import { SerializeAddon } from "@/addons/serialize" import { LocalPTY } from "@/context/terminal" import { resolveThemeVariant, useTheme } from "@opencode-ai/ui/theme" +import { MobileTerminalInput } from "./mobile-terminal-input" export interface TerminalProps extends ComponentProps<"div"> { pty: LocalPTY @@ -35,7 +36,13 @@ export const Terminal = (props: TerminalProps) => { const sdk = useSDK() const theme = useTheme() let container!: HTMLDivElement + let mobileInputRef: HTMLInputElement | undefined const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnectError"]) + const isCoarsePointer = window.matchMedia("(pointer: coarse)").matches + const isTouchDevice = "ontouchstart" in window + const isMobileInputEnabled = isCoarsePointer || isTouchDevice + const [socket, setSocket] = createSignal() + let isMounted = true let ws: WebSocket | undefined let term: Term | undefined let ghostty: Ghostty @@ -91,10 +98,11 @@ export const Terminal = (props: TerminalProps) => { const mod = await import("ghostty-web") ghostty = await mod.Ghostty.load() - const socket = new WebSocket( + const wsSocket = new WebSocket( sdk.url + `/pty/${local.pty.id}/connect?directory=${encodeURIComponent(sdk.directory)}`, ) - ws = socket + ws = wsSocket + setSocket(wsSocket) const t = new mod.Terminal({ cursorBlink: true, @@ -181,7 +189,7 @@ export const Terminal = (props: TerminalProps) => { handleResize = () => fitAddon.fit() window.addEventListener("resize", handleResize) t.onResize(async (size) => { - if (socket.readyState === WebSocket.OPEN) { + if (wsSocket.readyState === WebSocket.OPEN) { await sdk.client.pty .update({ ptyID: local.pty.id, @@ -194,8 +202,8 @@ export const Terminal = (props: TerminalProps) => { } }) t.onData((data) => { - if (socket.readyState === WebSocket.OPEN) { - socket.send(data) + if (wsSocket.readyState === WebSocket.OPEN) { + wsSocket.send(data) } }) t.onKey((key) => { @@ -206,7 +214,7 @@ export const Terminal = (props: TerminalProps) => { // t.onScroll((ydisp) => { // console.log("Scroll position:", ydisp) // }) - socket.addEventListener("open", () => { + wsSocket.addEventListener("open", () => { console.log("WebSocket connected") sdk.client.pty .update({ @@ -218,19 +226,20 @@ export const Terminal = (props: TerminalProps) => { }) .catch(() => {}) }) - socket.addEventListener("message", (event) => { + wsSocket.addEventListener("message", (event: MessageEvent) => { t.write(event.data) }) - socket.addEventListener("error", (error) => { + wsSocket.addEventListener("error", (error: Event) => { console.error("WebSocket error:", error) props.onConnectError?.(error) }) - socket.addEventListener("close", () => { + wsSocket.addEventListener("close", () => { console.log("WebSocket disconnected") }) }) onCleanup(() => { + isMounted = false if (handleResize) { window.removeEventListener("resize", handleResize) } @@ -252,6 +261,12 @@ export const Terminal = (props: TerminalProps) => { t?.dispose() }) + const handleContainerClick = () => { + if (isMobileInputEnabled && mobileInputRef) { + mobileInputRef.focus() + } + } + return (
{ classList={{ ...(local.classList ?? {}), "select-text": true, - "size-full px-6 py-3 font-mono": true, + "size-full px-3 sm:px-6 py-3 font-mono relative": true, [local.class ?? ""]: !!local.class, }} + onClick={handleContainerClick} {...others} - /> + > + + (mobileInputRef = el)} socket={socket()} enabled={isMounted} /> + +
) } diff --git a/packages/app/src/components/theme-picker.tsx b/packages/app/src/components/theme-picker.tsx new file mode 100644 index 00000000000..c10d85f8756 --- /dev/null +++ b/packages/app/src/components/theme-picker.tsx @@ -0,0 +1,88 @@ +import { createMemo, createSignal, onMount, Show } from "solid-js" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { Dialog } from "@opencode-ai/ui/dialog" +import { List } from "@opencode-ai/ui/list" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useLayout } from "@/context/layout" +import { THEMES, getThemeById, applyTheme, type Theme } from "@/theme/apply-theme" + +export function DialogSelectTheme(props: { originalTheme: string }) { + const layout = useLayout() + const dialog = useDialog() + const [previewTheme, setPreviewTheme] = createSignal(props.originalTheme) + const currentTheme = createMemo(() => getThemeById(previewTheme())) + + function handleSelect(theme: Theme | undefined) { + if (!theme) return + layout.theme.set(theme.id) + applyTheme(theme.id) + dialog.close() + } + + function handleActiveChange(theme: Theme | undefined) { + if (!theme) return + setPreviewTheme(theme.id) + applyTheme(theme.id) + } + + return ( + + t.id} + items={() => [...THEMES]} + current={currentTheme()} + filterKeys={["name", "id"]} + onSelect={handleSelect} + onActiveChange={handleActiveChange} + > + {(theme: Theme) => ( +
+ {theme.name} +
+ )} +
+
+ ) +} + +export function ThemePicker(props: { class?: string; mobile?: boolean }) { + const layout = useLayout() + const dialog = useDialog() + const currentTheme = createMemo(() => getThemeById(layout.theme.current())) + + onMount(() => applyTheme(currentTheme().id)) + + function openDialog() { + const originalTheme = currentTheme().id + dialog.show( + () => , + () => applyTheme(layout.theme.current()), + ) + } + + return ( + + + + } + > + + + ) +} diff --git a/packages/app/src/components/welcome-screen.tsx b/packages/app/src/components/welcome-screen.tsx new file mode 100644 index 00000000000..cc2172edd2d --- /dev/null +++ b/packages/app/src/components/welcome-screen.tsx @@ -0,0 +1,240 @@ +import { createEffect, createMemo, createSignal, onCleanup, Show, For } from "solid-js" +import { createStore, reconcile } from "solid-js/store" +import { AsciiLogo } from "@opencode-ai/ui/logo" +import { Button } from "@opencode-ai/ui/button" +import { TextField } from "@opencode-ai/ui/text-field" +import { Icon } from "@opencode-ai/ui/icon" +import { normalizeServerUrl, serverDisplayName, useServer } from "@/context/server" +import { usePlatform } from "@/context/platform" +import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" +import { isHostedEnvironment, hasUrlQueryParam, getUrlQueryParam } from "@/utils/hosted" + +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 interface WelcomeScreenProps { + attemptedUrl?: string + onRetry?: () => void +} + +export function WelcomeScreen(props: WelcomeScreenProps) { + const server = useServer() + const platform = usePlatform() + const [store, setStore] = createStore({ + url: "", + connecting: false, + error: "", + status: {} as Record, + }) + + const urlOverride = getUrlQueryParam() + const isLocalhost = () => { + const url = props.attemptedUrl || "" + return url.includes("localhost") || url.includes("127.0.0.1") + } + + const items = createMemo(() => { + const list = server.list + return list.filter((x) => x !== props.attemptedUrl) + }) + + 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(() => { + if (items().length === 0) return + refreshHealth() + const interval = setInterval(refreshHealth, 10_000) + onCleanup(() => clearInterval(interval)) + }) + + async function handleConnect(url: string, persist = false) { + const normalized = normalizeServerUrl(url) + if (!normalized) return + + setStore("connecting", true) + setStore("error", "") + + const result = await checkHealth(normalized, platform.fetch) + setStore("connecting", false) + + if (!result.healthy) { + setStore("error", "Could not connect to server") + return + } + + if (persist) { + server.add(normalized) + } else { + server.setActive(normalized) + } + props.onRetry?.() + } + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + const value = normalizeServerUrl(store.url) + if (!value) return + await handleConnect(value, true) + } + + return ( +
+
+ + +
+

Welcome to Shuvcode

+

+ {urlOverride + ? `Could not connect to the server at ${urlOverride}` + : "Connect to a Shuvcode server to get started"} +

+
+ + {/* Local Server Section */} +
+
+ +

Local Server

+
+ + +
+

Start a local server by running:

+ shuvcode +

or

+ npx shuvcode +
+
+ + +
+ + {/* Remote Server Section */} +
+
+ +

Remote Server

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

+ Note: Connecting to a remote server means trusting that server with your data. +

+
+ + {/* Saved Servers Section */} + 0}> +
+

Saved Servers

+
+ + {(url) => ( + + )} + +
+
+
+ + {/* Troubleshooting Section */} + +
+ Troubleshooting +
+

+ Server not running: Make sure you have a Shuvcode server running locally or accessible + remotely. +

+

+ CORS blocked: The server must allow requests from{" "} + {location.origin}. Local servers automatically allow + this domain. +

+

+ Mixed content: If connecting to an http:// server from this{" "} + https:// page, your browser may block the connection. Use https:// for remote + servers. +

+
+
+
+ + +

Version: {platform.version}

+
+
+
+ ) +} diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index a0656c5fc60..84b9007c778 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -7,6 +7,8 @@ import { type Path, type Project, type FileDiff, + type File, + type FileNode, type Todo, type SessionStatus, type ProviderListResponse, @@ -23,9 +25,12 @@ 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 { WelcomeScreen } from "../components/welcome-screen" import { batch, createContext, useContext, onCleanup, onMount, type ParentProps, Switch, Match } from "solid-js" import { showToast } from "@opencode-ai/ui/toast" import { getFilename } from "@opencode-ai/util/path" +import { isHostedEnvironment } from "@/utils/hosted" +import { useServer } from "./server" type State = { status: "loading" | "partial" | "complete" @@ -45,6 +50,8 @@ type State = { todo: { [sessionID: string]: Todo[] } + changes: File[] + node: FileNode[] permission: { [sessionID: string]: PermissionRequest[] } @@ -62,17 +69,24 @@ type State = { } } +type ConnectionState = "connecting" | "ready" | "needs_config" | "error" + function createGlobalSync() { const globalSDK = useGlobalSDK() + const server = useServer() const [globalStore, setGlobalStore] = createStore<{ + connectionState: ConnectionState ready: boolean error?: InitError + attemptedUrl?: string path: Path project: Project[] provider: ProviderListResponse provider_auth: ProviderAuthResponse }>({ + connectionState: "connecting", ready: false, + attemptedUrl: undefined, path: { state: "", config: "", worktree: "", directory: "", home: "" }, project: [], provider: { all: [], connected: [], default: {} }, @@ -95,11 +109,13 @@ function createGlobalSync() { session_status: {}, session_diff: {}, todo: {}, + changes: [], + node: [], permission: {}, mcp: {}, lsp: [], vcs: undefined, - limit: 5, + limit: 10, message: {}, part: {}, }) @@ -114,7 +130,8 @@ function createGlobalSync() { .list({ directory }) .then((x) => { const fourHoursAgo = Date.now() - 4 * 60 * 60 * 1000 - const nonArchived = (x.data ?? []) +const data = Array.isArray(x.data) ? x.data : [] + const nonArchived = data .filter((s) => !!s?.id) .filter((s) => !s.time?.archived) .slice() @@ -406,16 +423,46 @@ function createGlobalSync() { }) onCleanup(unsub) + /** + * Probes the server health with a short timeout (2 seconds). + * Used for initial connection to provide quick feedback. + */ + async function probeHealth( + url: string, + healthFn: () => Promise<{ data?: { healthy?: boolean } }>, + ): Promise<{ healthy: boolean }> { + try { + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), 2000) + + const result = await healthFn() + clearTimeout(timeoutId) + + return { healthy: result.data?.healthy === true } + } catch { + return { healthy: false } + } + } + async function bootstrap() { - const health = await globalSDK.client.global - .health() - .then((x) => x.data) - .catch(() => undefined) - if (!health?.healthy) { + setGlobalStore("connectionState", "connecting") + setGlobalStore("attemptedUrl", globalSDK.url) + + // Use a short timeout for the health probe (2 seconds) + const probeResult = await probeHealth(globalSDK.url, () => globalSDK.client.global.health()) + + if (!probeResult.healthy) { + // For hosted environments, show the welcome/configuration screen + if (isHostedEnvironment()) { + setGlobalStore("connectionState", "needs_config") + return + } + // For non-hosted environments, show the error page setGlobalStore( "error", new Error(`Could not connect to server. Is there a server running at \`${globalSDK.url}\`?`), ) + setGlobalStore("connectionState", "error") return } @@ -427,7 +474,8 @@ function createGlobalSync() { ), retry(() => globalSDK.client.project.list().then(async (x) => { - const projects = (x.data ?? []) +const data = Array.isArray(x.data) ? x.data : [] + const projects = data .filter((p) => !!p?.id) .filter((p) => !!p.worktree && !p.worktree.includes("opencode-test")) .slice() @@ -455,8 +503,14 @@ function createGlobalSync() { }), ), ]) - .then(() => setGlobalStore("ready", true)) - .catch((e) => setGlobalStore("error", e)) + .then(() => { + setGlobalStore("ready", true) + setGlobalStore("connectionState", "ready") + }) + .catch((e) => { + setGlobalStore("error", e) + setGlobalStore("connectionState", "error") + }) } onMount(() => { @@ -471,6 +525,12 @@ function createGlobalSync() { get error() { return globalStore.error }, + get connectionState() { + return globalStore.connectionState + }, + get attemptedUrl() { + return globalStore.attemptedUrl + }, child, bootstrap, project: { @@ -485,10 +545,18 @@ export function GlobalSyncProvider(props: ParentProps) { const value = createGlobalSync() return ( - + +
+
Connecting to server...
+
+
+ + value.bootstrap()} /> + + - + {props.children}
diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index def933c39a3..efdb0405d1c 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -6,12 +6,26 @@ import { useGlobalSDK } from "./global-sdk" import { useServer } from "./server" import { Project } from "@opencode-ai/sdk/v2" import { persisted } from "@/utils/persist" +import { applyTheme, DEFAULT_THEME_ID } from "@/theme/apply-theme" +import { applyFontWithLoad } from "@/fonts/apply-font" +import { getFontById, FONTS } from "@/fonts/font-definitions" import { same } from "@/utils/same" import { createScrollPersistence, type SessionScroll } from "./layout-scroll" +export const REVIEW_PANE = { + DEFAULT_WIDTH: 450, + MIN_WIDTH: 200, + MAX_WIDTH_RATIO: 0.5, +} as const + const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const export type AvatarColorKey = (typeof AVATAR_COLOR_KEYS)[number] +type SessionTabs = { + active?: string + all: string[] +} + export function getAvatarColors(key?: string) { if (key && AVATAR_COLOR_KEYS.includes(key as AvatarColorKey)) { return { @@ -25,10 +39,7 @@ export function getAvatarColors(key?: string) { } } -type SessionTabs = { - active?: string - all: string[] -} +type Dialog = "provider" | "model" | "connect" type SessionView = { scroll: Record @@ -37,6 +48,7 @@ type SessionView = { export type LocalProject = Partial & { worktree: string; expanded: boolean } +export type ExpandedSessions = Record export type ReviewDiffStyle = "unified" | "split" export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({ @@ -57,17 +69,22 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( height: 280, }, review: { - opened: true, + opened: false, + state: "pane" as "pane" | "tab", + width: REVIEW_PANE.DEFAULT_WIDTH as number, diffStyle: "split" as ReviewDiffStyle, }, session: { width: 600, }, + theme: DEFAULT_THEME_ID, + font: FONTS[0].id, mobileSidebar: { opened: false, }, sessionTabs: {} as Record, sessionView: {} as Record, + expandedSessions: {} as ExpandedSessions, }), ) @@ -235,11 +252,26 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( const list = createMemo(() => enriched().flatMap(colorize)) onMount(() => { + // Load project sessions Promise.all( server.projects.list().map((project) => { return globalSync.project.loadSessions(project.worktree) }), ) + + // Normalize persisted review state (ensure opened defaults to false for old/missing state) + if (store.review === undefined || store.review.opened === undefined) { + setStore("review", "opened", false) + } + }) + + createEffect(() => { + applyTheme(store.theme) + }) + + createEffect(() => { + const font = getFontById(store.font) ?? FONTS[0] + applyFontWithLoad(font) }) return { @@ -299,6 +331,8 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( }, review: { opened: createMemo(() => store.review?.opened ?? true), + state: createMemo(() => store.review?.state ?? "pane"), + width: createMemo(() => store.review?.width ?? 450), diffStyle: createMemo(() => store.review?.diffStyle ?? "split"), setDiffStyle(diffStyle: ReviewDiffStyle) { if (!store.review) { @@ -316,10 +350,20 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( toggle() { setStore("review", "opened", (x) => !x) }, + pane() { + setStore("review", "state", "pane") + }, + tab() { + setStore("review", "state", "tab") + }, + resize(width: number) { + setStore("review", "width", width) + }, }, session: { width: createMemo(() => store.session?.width ?? 600), resize(width: number) { + // ResizeHandle already enforces min/max constraints if (!store.session) { setStore("session", { width }) return @@ -327,6 +371,18 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( setStore("session", "width", width) }, }, + theme: { + current: createMemo(() => store.theme), + set(theme: string) { + setStore("theme", theme) + }, + }, + font: { + current: createMemo(() => store.font), + set(font: string) { + setStore("font", font) + }, + }, mobileSidebar: { opened: createMemo(() => store.mobileSidebar?.opened ?? false), show() { @@ -365,6 +421,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( }, } }, + tabs(sessionKey: string) { touch(sessionKey) const tabs = createMemo(() => store.sessionTabs[sessionKey] ?? { all: [] }) diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx index 3af840556ee..41250e80da5 100644 --- a/packages/app/src/context/local.tsx +++ b/packages/app/src/context/local.tsx @@ -412,9 +412,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const fetch = async (path: string) => { const relativePath = relative(path) const parent = relativePath.split("/").slice(0, -1).join("/") - if (parent) { - await list(parent) - } + // Always list the parent directory, including root ("") for top-level files + await list(parent) } const init = async (path: string) => { diff --git a/packages/app/src/context/platform.tsx b/packages/app/src/context/platform.tsx index 7fcbb620ac1..aba1e515c46 100644 --- a/packages/app/src/context/platform.tsx +++ b/packages/app/src/context/platform.tsx @@ -1,6 +1,16 @@ import { createSimpleContext } from "@opencode-ai/ui/context" import { AsyncStorage, SyncStorage } from "@solid-primitives/storage" +/** Check if running as installed PWA (standalone mode) */ +export function isPWA(): boolean { + if (typeof window === "undefined") return false + return ( + window.matchMedia("(display-mode: standalone)").matches || + // @ts-ignore - iOS Safari specific + window.navigator.standalone === true + ) +} + export type Platform = { /** Platform discriminator */ platform: "web" | "desktop" diff --git a/packages/app/src/context/server.tsx b/packages/app/src/context/server.tsx index 48e7e99cceb..9d3e70986d6 100644 --- a/packages/app/src/context/server.tsx +++ b/packages/app/src/context/server.tsx @@ -11,7 +11,11 @@ export function normalizeServerUrl(input: string) { const trimmed = input.trim() if (!trimmed) return const withProtocol = /^https?:\/\//.test(trimmed) ? trimmed : `http://${trimmed}` - return withProtocol.replace(/\/+$/, "") + const cleaned = withProtocol.replace(/\/+$/, "") + if ((cleaned === "http:" || cleaned === "https:") && typeof window !== "undefined") { + return window.location.origin + } + return cleaned.replace(/^(https?:\/\/[^/]+).*/, "$1") } export function serverDisplayName(url: string) { @@ -35,10 +39,11 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( const platform = usePlatform() const [store, setStore, _, ready] = persisted( - "server.v3", + "server.v4", createStore({ list: [] as string[], projects: {} as Record, + active: "" as string, // Persist the last active server }), ) @@ -47,7 +52,10 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( function setActive(input: string) { const url = normalizeServerUrl(input) if (!url) return - setActiveRaw(url) + batch(() => { + setActiveRaw(url) + setStore("active", url) // Persist active server + }) } function add(input: string) { @@ -56,7 +64,10 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( const fallback = normalizeServerUrl(props.defaultUrl) if (fallback && url === fallback) { - setActiveRaw(url) + batch(() => { + setActiveRaw(url) + setStore("active", url) + }) return } @@ -65,6 +76,7 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( setStore("list", store.list.length, url) } setActiveRaw(url) + setStore("active", url) }) } @@ -78,13 +90,17 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( batch(() => { setStore("list", list) setActiveRaw(next) + setStore("active", next) }) } + // Initialize active server from persisted state or default createEffect(() => { if (!ready()) return if (active()) return - const url = normalizeServerUrl(props.defaultUrl) + // Priority: persisted active > default URL + const persistedActive = store.active ? normalizeServerUrl(store.active) : undefined + const url = persistedActive || normalizeServerUrl(props.defaultUrl) if (!url) return setActiveRaw(url) }) diff --git a/packages/app/src/context/sync.tsx b/packages/app/src/context/sync.tsx index a237871f984..fc5c638ed3c 100644 --- a/packages/app/src/context/sync.tsx +++ b/packages/app/src/context/sync.tsx @@ -13,6 +13,31 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const globalSync = useGlobalSync() const sdk = useSDK() const [store, setStore] = globalSync.child(sdk.directory) + + const load = { + project: () => sdk.client.project.current().then((x) => setStore("project", x.data!.id)), + provider: () => + sdk.client.provider.list().then((x) => setStore("provider", x.data ?? { all: [], connected: [], default: {} })), + path: () => sdk.client.path.get().then((x) => setStore("path", x.data!)), + agent: () => sdk.client.app.agents().then((x) => setStore("agent", x.data ?? [])), + session: () => + sdk.client.session.list().then((x) => { + const sessions = (x.data ?? []) + .slice() + .filter((s) => !s.time.archived) + .sort((a, b) => a.id.localeCompare(b.id)) + .slice(0, store.limit) + setStore("session", sessions) + }), + status: () => sdk.client.session.status().then((x) => setStore("session_status", x.data!)), + config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)), + changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)), + node: () => sdk.client.file.list({ path: "/" }).then((x) => setStore("node", x.data!)), + command: () => sdk.client.command.list().then((x) => setStore("command", x.data ?? [])), + } + + Promise.all(Object.values(load).map((p) => p())).then(() => setStore("status", "complete")) + const absolute = (path: string) => (store.path.directory + "/" + path).replace("//", "/") return { @@ -125,6 +150,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const sessions = (x.data ?? []) .filter((s) => !!s?.id) .slice() + .filter((s) => !s.time.archived) .sort((a, b) => a.id.localeCompare(b.id)) .slice(0, store.limit) setStore("session", reconcile(sessions, { key: "id" })) diff --git a/packages/app/src/env.d.ts b/packages/app/src/env.d.ts index ad575e93b4a..bc8342b1b2f 100644 --- a/packages/app/src/env.d.ts +++ b/packages/app/src/env.d.ts @@ -6,3 +6,6 @@ interface ImportMetaEnv { interface ImportMeta { readonly env: ImportMetaEnv } + +declare const __APP_VERSION__: string +declare const __COMMIT_HASH__: string diff --git a/packages/app/src/fonts/apply-font.ts b/packages/app/src/fonts/apply-font.ts new file mode 100644 index 00000000000..cf3de1f2517 --- /dev/null +++ b/packages/app/src/fonts/apply-font.ts @@ -0,0 +1,31 @@ +import { FONTS, getFontById, type FontDefinition } from "@/fonts/font-definitions" +import { loadFont } from "@/fonts/font-loader" + +function applyFontDefinition(font: FontDefinition): void { + const fontFamily = `"${font.family}", ${font.fallback}` + document.documentElement.style.setProperty("--font-family-sans", fontFamily) +} + +export function applyFont(fontId: string): void { + const font = getFontById(fontId) ?? FONTS[0] + applyFontDefinition(font) +} + +export async function ensureFontLoaded(font: FontDefinition): Promise { + if (!font.googleFontsUrl) return true + try { + await loadFont(font) + return true + } catch { + return false + } +} + +export async function applyFontWithLoad(font: FontDefinition): Promise { + const loaded = await ensureFontLoaded(font) + if (loaded) { + applyFontDefinition(font) + } else { + applyFontDefinition(FONTS[0]) + } +} diff --git a/packages/app/src/fonts/font-definitions.ts b/packages/app/src/fonts/font-definitions.ts new file mode 100644 index 00000000000..d7788e4eb8d --- /dev/null +++ b/packages/app/src/fonts/font-definitions.ts @@ -0,0 +1,93 @@ +export type FontDefinition = { + id: string + name: string + family: string + googleFontsUrl: string // Empty string for fonts already loaded + fallback: string +} + +export const DEFAULT_FONT_ID = "meslo" + +export const FONTS: FontDefinition[] = [ + { + id: "meslo", + name: "Meslo", + family: "meslo", + googleFontsUrl: "", // Already loaded via jsDelivr in index.html + fallback: '"Menlo", "Monaco", "Courier New", monospace', + }, + { + id: "geist", + name: "Geist", + family: "Geist", + googleFontsUrl: "", // Already bundled in UI package + fallback: '"Geist Fallback", sans-serif', + }, + { + id: "inter", + name: "Inter", + family: "Inter", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap", + fallback: "sans-serif", + }, + { + id: "nunito", + name: "Nunito", + family: "Nunito", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;700&display=swap", + fallback: "sans-serif", + }, + { + id: "roboto-condensed", + name: "Roboto Condensed", + family: "Roboto Condensed", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&display=swap", + fallback: "sans-serif", + }, + { + id: "oswald", + name: "Oswald", + family: "Oswald", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;700&display=swap", + fallback: "sans-serif", + }, + { + id: "forum", + name: "Forum", + family: "Forum", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Forum&display=swap", + fallback: "serif", + }, + { + id: "rubik", + name: "Rubik", + family: "Rubik", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Rubik:wght@400;500;700&display=swap", + fallback: "sans-serif", + }, + { + id: "ubuntu-mono", + name: "Ubuntu Mono", + family: "Ubuntu Mono", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Ubuntu+Mono:wght@400;700&display=swap", + fallback: "monospace", + }, + { + id: "jetbrains-mono", + name: "JetBrains Mono", + family: "JetBrains Mono", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap", + fallback: "monospace", + }, + { + id: "inconsolata", + name: "Inconsolata", + family: "Inconsolata", + googleFontsUrl: "https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;500;700&display=swap", + fallback: "monospace", + }, +] + +export function getFontById(id: string): FontDefinition | undefined { + return FONTS.find((f) => f.id === id) +} diff --git a/packages/app/src/fonts/font-loader.ts b/packages/app/src/fonts/font-loader.ts new file mode 100644 index 00000000000..366d5ac2b00 --- /dev/null +++ b/packages/app/src/fonts/font-loader.ts @@ -0,0 +1,52 @@ +import type { FontDefinition } from "./font-definitions" + +const loadedFonts = new Set() +const loadingFonts = new Map>() + +export async function loadFont(font: FontDefinition): Promise { + // Skip if already loaded or if it's a bundled font (no Google Fonts URL) + if (loadedFonts.has(font.id) || !font.googleFontsUrl) { + return + } + + // Return existing promise if already loading + const existingPromise = loadingFonts.get(font.id) + if (existingPromise) { + return existingPromise + } + + const loadPromise = new Promise((resolve, reject) => { + // Check if link already exists in the document + const existingLink = document.querySelector(`link[data-font-id="${font.id}"]`) + if (existingLink) { + loadedFonts.add(font.id) + resolve() + return + } + + const link = document.createElement("link") + link.rel = "stylesheet" + link.href = font.googleFontsUrl + link.setAttribute("data-font-id", font.id) + + link.onload = () => { + loadedFonts.add(font.id) + loadingFonts.delete(font.id) + resolve() + } + + link.onerror = () => { + loadingFonts.delete(font.id) + reject(new Error(`Failed to load font: ${font.name}`)) + } + + document.head.appendChild(link) + }) + + loadingFonts.set(font.id, loadPromise) + return loadPromise +} + +export function isFontLoaded(fontId: string): boolean { + return loadedFonts.has(fontId) +} diff --git a/packages/app/src/hooks/use-keyboard-visibility.tsx b/packages/app/src/hooks/use-keyboard-visibility.tsx new file mode 100644 index 00000000000..57e9d3ae1ec --- /dev/null +++ b/packages/app/src/hooks/use-keyboard-visibility.tsx @@ -0,0 +1,44 @@ +import { createSignal, onMount, onCleanup } from "solid-js" + +export function useKeyboardVisibility() { + const [keyboardHeight, setKeyboardHeight] = createSignal(0) + const [isKeyboardVisible, setIsKeyboardVisible] = createSignal(false) + + onMount(() => { + if (!window.visualViewport) return + + const handleResize = () => { + const height = window.innerHeight - window.visualViewport!.height + const clamped = Math.max(0, height) + setKeyboardHeight(clamped) + const visible = clamped > 100 + setIsKeyboardVisible(visible) + document.documentElement.style.setProperty("--keyboard-offset", `${clamped}px`) + + // Set data attribute on document element for CSS targeting + if (visible) { + document.documentElement.setAttribute("data-keyboard-visible", "true") + } else { + document.documentElement.removeAttribute("data-keyboard-visible") + } + } + + const handleScroll = () => { + // Recalculate on scroll to handle iOS PWA viewport changes + const height = window.innerHeight - window.visualViewport!.height + const clamped = Math.max(0, height) + document.documentElement.style.setProperty("--keyboard-offset", `${clamped}px`) + } + + window.visualViewport.addEventListener("resize", handleResize) + window.visualViewport.addEventListener("scroll", handleScroll) + onCleanup(() => { + window.visualViewport?.removeEventListener("resize", handleResize) + window.visualViewport?.removeEventListener("scroll", handleScroll) + // Clean up the data attribute + document.documentElement.removeAttribute("data-keyboard-visible") + }) + }) + + return { keyboardHeight, isKeyboardVisible } +} diff --git a/packages/app/src/hooks/use-providers.ts b/packages/app/src/hooks/use-providers.ts index 4a73fa05588..4fa077a9ccf 100644 --- a/packages/app/src/hooks/use-providers.ts +++ b/packages/app/src/hooks/use-providers.ts @@ -16,14 +16,14 @@ export function useProviders() { } return globalSync.data.provider }) - const connected = createMemo(() => providers().all.filter((p) => providers().connected.includes(p.id))) + 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))) + const popular = createMemo(() => (providers().all ?? []).filter((p) => popularProviders.includes(p.id))) return { - all: createMemo(() => providers().all), - default: createMemo(() => providers().default), + all: createMemo(() => providers().all ?? []), + default: createMemo(() => providers().default ?? {}), popular, connected, paid, diff --git a/packages/app/src/index.css b/packages/app/src/index.css index e40f0842b15..8f6106d28e9 100644 --- a/packages/app/src/index.css +++ b/packages/app/src/index.css @@ -1,7 +1,147 @@ @import "@opencode-ai/ui/styles/tailwind"; :root { + /* Font is set via JavaScript in index.html and font-picker.tsx */ + /* Default fallback handled in inline script */ + + /* Safe area insets for mobile devices (notch, home indicator, etc.) */ + --safe-area-inset-top: env(safe-area-inset-top, 0px); + --safe-area-inset-bottom: env(safe-area-inset-bottom, 0px); + --safe-area-inset-left: env(safe-area-inset-left, 0px); + --safe-area-inset-right: env(safe-area-inset-right, 0px); + + /* Keyboard offset for mobile terminal */ + --keyboard-offset: 0px; +} + +/* When keyboard is visible, adjust the main app container to shrink and stay above keyboard */ +[data-keyboard-visible="true"] #root { + height: calc(100% - var(--keyboard-offset)); + overflow: hidden; +} + +/* For fullscreen mobile terminal overlay, adjust bottom position when keyboard is visible */ +[data-component="mobile-terminal-fullscreen"][data-keyboard-visible="true"] { + bottom: var(--keyboard-offset); +} + +a { + cursor: default; +} + +/* Mobile breakpoint: 40rem = 640px */ +@media (max-width: 40rem) { + /* Prevent zoom on input focus */ + input, + textarea, + select, + button, + [contenteditable] { + font-size: 16px; + } + + /* Full-screen dialogs on mobile */ + [data-component="dialog"] { + margin-left: 0 !important; + padding: var(--safe-area-inset-top) var(--safe-area-inset-right) var(--safe-area-inset-bottom) + var(--safe-area-inset-left); + + [data-slot="dialog-container"] { + width: 100% !important; + height: 100% !important; + max-width: 100% !important; + max-height: 100% !important; + + &[data-size="sm"], + &[data-size="md"], + &[data-size="lg"] { + width: 100% !important; + height: 100% !important; + max-width: 100% !important; + max-height: 100% !important; + } + + [data-slot="dialog-content"] { + border-radius: 0; + border: none; + min-height: 100%; + height: 100%; + } + } + } + + /* Mobile header adjustments */ + header[data-tauri-drag-region] { + /* Padding handled by layout wrapper */ + } +} + +/* Ensure proper background and sizing */ +html, +body { + background-color: var(--background-base); + height: 100%; +} + +#root { + height: 100%; +} + +/* PWA standalone mode specific styles */ +@media (display-mode: standalone) { + :root { + /* When running as PWA, ensure we account for device UI */ + --pwa-top-offset: var(--safe-area-inset-top); + --pwa-bottom-offset: var(--safe-area-inset-bottom); + } + + /* Ensure the app fills the screen properly in PWA mode */ + #root { + min-height: 100vh; + min-height: -webkit-fill-available; + min-height: 100dvh; + } + + .home-menu-button { + top: var(--safe-area-inset-top); + } + + .session-scroll-container { + overscroll-behavior: contain; + } +} + +/* PWA standalone mode - safe area handling for iOS */ +@media (display-mode: standalone) { + /* Header should clear the Dynamic Island */ + header[data-tauri-drag-region] { + padding-top: var(--safe-area-inset-top); + min-height: calc(3rem + var(--safe-area-inset-top)); + } +} + +/* Mobile PWA prompt container bottom padding */ +@media (display-mode: standalone) and (max-width: 40rem) { + /* Adjust bottom positioning for mobile prompt input */ + [data-component="prompt-dock"] { + padding-bottom: max(1.5rem, var(--safe-area-inset-bottom)); + } +} + +/* Touch-friendly improvements */ +@media (pointer: coarse) { + /* Larger touch targets */ + button, + [role="button"], a { - cursor: default; + min-height: 44px; + min-width: 44px; + } + + /* Exception for inline/small buttons that are part of larger components */ + [data-slot="icon-button"], + [data-component="icon-button"] { + min-height: 32px; + min-width: 32px; } } diff --git a/packages/app/src/pages/error.tsx b/packages/app/src/pages/error.tsx index 4326206d842..ba1b9cd2654 100644 --- a/packages/app/src/pages/error.tsx +++ b/packages/app/src/pages/error.tsx @@ -1,5 +1,5 @@ import { TextField } from "@opencode-ai/ui/text-field" -import { Logo } from "@opencode-ai/ui/logo" +import { AsciiLogo } from "@opencode-ai/ui/logo" import { Button } from "@opencode-ai/ui/button" import { Component, Show } from "solid-js" import { createStore } from "solid-js/store" @@ -204,7 +204,7 @@ export const ErrorPage: Component = (props) => { return (
- +

Something went wrong

An error occurred while loading the application.

@@ -239,11 +239,11 @@ export const ErrorPage: Component = (props) => {
- Please report this error to the OpenCode team + Please report this error to the shuvcode team 0}> -
-
+
+
Recent projects
-
    (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)) - .slice(0, 5)} + .slice(0, 10)} > {(project) => ( )} @@ -108,11 +99,11 @@ export default function Home() {
    No recent projects
    -
    Get started by opening a local project
    +
    Get started by adding a project
    -
    diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 9320267944d..8940846b0a1 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -1,22 +1,13 @@ -import { - createEffect, - createMemo, - createSignal, - For, - Match, - onCleanup, - onMount, - ParentProps, - Show, - Switch, - untrack, - type JSX, -} from "solid-js" +import { createEffect, createMemo, createSignal, For, Match, onCleanup, onMount, ParentProps, Show, Switch, untrack, type JSX } from "solid-js" import { DateTime } from "luxon" import { A, useNavigate, useParams } from "@solidjs/router" import { useLayout, getAvatarColors, LocalProject } from "@/context/layout" import { useGlobalSync } from "@/context/global-sync" import { base64Decode, base64Encode } from "@opencode-ai/util/encode" +import { AsciiLogo, AsciiMark } from "@opencode-ai/ui/logo" +import { ThemePicker } from "@/components/theme-picker" +import { FontPicker } from "@/components/font-picker" +import { Select } from "@opencode-ai/ui/select" import { Avatar } from "@opencode-ai/ui/avatar" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Button } from "@opencode-ai/ui/button" @@ -26,11 +17,11 @@ import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { Collapsible } from "@opencode-ai/ui/collapsible" import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { Spinner } from "@opencode-ai/ui/spinner" -import { Mark } from "@opencode-ai/ui/logo" + import { getFilename } from "@opencode-ai/util/path" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { Session } from "@opencode-ai/sdk/v2/client" -import { usePlatform } from "@/context/platform" +import { usePlatform, isPWA } from "@/context/platform" import { createStore, produce } from "solid-js/store" import { DragDropProvider, @@ -47,15 +38,20 @@ import { useGlobalSDK } from "@/context/global-sdk" import { useNotification } from "@/context/notification" import { usePermission } from "@/context/permission" import { Binary } from "@opencode-ai/util/binary" +import { PullToRefresh } from "@/components/pull-to-refresh" 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 { DialogCreateProject } from "@/components/dialog-create-project" +import { DialogSessionRenameGlobal } from "@/components/dialog-session-rename-global" + +import { DialogSelectTheme } from "@/components/theme-picker" import { DialogEditProject } from "@/components/dialog-edit-project" +import { applyTheme } from "@/theme/apply-theme" import { DialogSelectServer } from "@/components/dialog-select-server" import { useCommand, type CommandOption } from "@/context/command" import { ConstrainDragXAxis } from "@/utils/solid-dnd" -import { DialogSelectDirectory } from "@/components/dialog-select-directory" import { useServer } from "@/context/server" export default function Layout(props: ParentProps) { @@ -161,6 +157,16 @@ export default function Layout(props: ParentProps) { onCleanup(() => clearInterval(interval)) }) + const currentDirectory = createMemo(() => base64Decode(params.dir ?? "")) + const sessions = createMemo(() => { + const dir = currentDirectory() + if (!dir) return [] + return globalSync.child(dir)[0].session ?? [] + }) + const currentSession = createMemo(() => sessions().find((s) => s.id === params.id)) + const currentSessionId = createMemo(() => currentSession()?.id) + const otherSessions = createMemo(() => sessions().filter((s) => s.id !== currentSessionId())) + onMount(() => { const toastBySession = new Map() const alertedAtBySession = new Map() @@ -245,6 +251,28 @@ export default function Layout(props: ParentProps) { }) }) + function flattenSessions(sessions: Session[]): Session[] { + const childrenMap = new Map() + for (const session of sessions) { + if (session.parentID) { + const children = childrenMap.get(session.parentID) ?? [] + children.push(session) + childrenMap.set(session.parentID, children) + } + } + const result: Session[] = [] + function visit(session: Session) { + result.push(session) + for (const child of childrenMap.get(session.id) ?? []) { + visit(child) + } + } + for (const session of sessions) { + if (!session.parentID) visit(session) + } + return result + } + function sortSessions(a: Session, b: Session) { const now = Date.now() const oneMinuteAgo = now - 60 * 1000 @@ -262,14 +290,16 @@ export default function Layout(props: ParentProps) { if (!scrollContainerRef) return const element = scrollContainerRef.querySelector(`[data-session-id="${sessionId}"]`) if (element) { - element.scrollIntoView({ block: "nearest", behavior: "smooth" }) + element.scrollIntoView({ block: "center", behavior: "smooth" }) } } function projectSessions(directory: string) { if (!directory) return [] - const sessions = globalSync.child(directory)[0].session.toSorted(sortSessions) - return (sessions ?? []).filter((s) => !s.parentID) + const sessions = globalSync + .child(directory)[0] + .session.toSorted((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)) + return flattenSessions(sessions ?? []) } const currentSessions = createMemo(() => { @@ -358,13 +388,8 @@ export default function Layout(props: ParentProps) { keybind: "mod+b", onSelect: () => layout.sidebar.toggle(), }, - { - id: "project.open", - title: "Open project", - category: "Project", - keybind: "mod+o", - onSelect: () => chooseProject(), - }, + + { id: "provider.connect", title: "Connect provider", @@ -402,6 +427,15 @@ export default function Layout(props: ParentProps) { if (session) archiveSession(session) }, }, + { + id: "theme.picker", + title: "Theme picker", + category: "Theme", + onSelect: () => { + const originalTheme = theme.themeId() + dialog.show(() => , () => applyTheme(theme.themeId())) + }, + }, { id: "theme.cycle", title: "Cycle theme", @@ -409,41 +443,14 @@ export default function Layout(props: ParentProps) { keybind: "mod+shift+t", onSelect: () => cycleTheme(1), }, - ] - - for (const [id, definition] of availableThemeEntries()) { - commands.push({ - id: `theme.set.${id}`, - title: `Use theme: ${definition.name ?? id}`, - category: "Theme", - onSelect: () => theme.commitPreview(), - onHighlight: () => { - theme.previewTheme(id) - return () => theme.cancelPreview() - }, - }) - } - - commands.push({ - id: "theme.scheme.cycle", - title: "Cycle color scheme", - category: "Theme", - keybind: "mod+shift+s", - onSelect: () => cycleColorScheme(1), - }) - - for (const scheme of colorSchemeOrder) { - commands.push({ - id: `theme.scheme.${scheme}`, - title: `Use color scheme: ${colorSchemeLabel[scheme]}`, + { + id: "theme.scheme.cycle", + title: "Cycle color scheme", category: "Theme", - onSelect: () => theme.commitPreview(), - onHighlight: () => { - theme.previewColorScheme(scheme) - return () => theme.cancelPreview() - }, - }) - } + keybind: "mod+shift+s", + onSelect: () => cycleColorScheme(1), + }, + ] return commands }) @@ -456,6 +463,10 @@ export default function Layout(props: ParentProps) { dialog.show(() => ) } + function createProject() { + dialog.show(() => ) + } + function navigateToProject(directory: string | undefined) { if (!directory) return const lastSession = store.lastSession[directory] @@ -482,32 +493,6 @@ export default function Layout(props: ParentProps) { 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: "Open project", - multiple: true, - }) - resolve(result) - } else { - dialog.show( - () => , - () => resolve(null), - ) - } - } - createEffect(() => { if (!params.dir || !params.id) return const directory = base64Decode(params.dir) @@ -519,12 +504,8 @@ export default function Layout(props: ParentProps) { }) createEffect(() => { - if (isLargeViewport()) { - const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 48 - document.documentElement.style.setProperty("--dialog-left-margin", `${sidebarWidth}px`) - } else { - document.documentElement.style.setProperty("--dialog-left-margin", "0px") - } + const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 48 + document.documentElement.style.setProperty("--dialog-left-margin", `${sidebarWidth}px`) }) function getDraggableId(event: unknown): string | undefined { @@ -639,17 +620,25 @@ export default function Layout(props: ParentProps) { slug: string project: LocalProject mobile?: boolean + depth?: number + allSessions: Session[] }): JSX.Element => { const notification = useNotification() + const depth = () => props.depth ?? 0 const updated = createMemo(() => DateTime.fromMillis(props.session.time.updated)) 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 childSessions = createMemo(() => + props.allSessions.filter((s) => s.parentID === props.session.id).toSorted(sortSessions), + ) + const hasChildren = createMemo(() => childSessions().length > 0) + // TODO: Re-enable layout.sessions.isExpanded when layout context is merged + const isExpanded = createMemo(() => true) 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) { + for (const child of childSessions()) { const childPermissions = sessionStore.permission?.[child.id] ?? [] if (childPermissions.length > 0) return true } @@ -661,19 +650,33 @@ export default function Layout(props: ParentProps) { const status = sessionStore.session_status[props.session.id] return status?.type === "busy" || status?.type === "retry" }) - return ( - <> -
    - - -
    + + const SessionRow = () => ( +
    { + // TODO: Re-enable layout.sessions.toggle when layout context is merged + // hasChildren() && layout.sessions.toggle(props.session.id) + }} + > + + +
    +
    + }> + + {props.session.title} -
    - - - - - -
    - - -
    - - 0}> -
    - - - - {Math.abs(updated().diffNow().as("seconds")) < 60 - ? "Now" - : updated() - .toRelative({ - style: "short", - unit: ["days", "hours", "minutes"], - }) - ?.replace(" ago", "") - ?.replace(/ days?/, "d") - ?.replace(" min.", "m") - ?.replace(" hr.", "h")} - - - -
    - -
    - {`${props.session.summary?.files || "No"} file${props.session.summary?.files !== 1 ? "s" : ""} changed`} - {(summary) => } -
    -
    -
    +
    + + + + + +
    + + +
    + + 0}> +
    + + + + {Math.abs(updated().diffNow().as("seconds")) < 60 + ? "Now" + : updated() + .toRelative({ + style: "short", + unit: ["days", "hours", "minutes"], + }) + ?.replace(" ago", "") + ?.replace(/ days?/, "d") + ?.replace(" min.", "m") + ?.replace(" hr.", "h")} + + + +
    +
    + +
    + {`${props.session.summary?.files || "No"} file${props.session.summary?.files !== 1 ? "s" : ""} changed`} + {(summary) => } +
    +
    + + + + } + > + archiveSession(props.session)} /> -
    +
    + ) + + return ( + <> + + + + {(child) => ( + + )} + + ) } const SortableProject = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => { const sortable = createSortable(props.project.worktree) - const showExpanded = createMemo(() => props.mobile || layout.sidebar.opened()) + const slug = createMemo(() => base64Encode(props.project.worktree)) const defaultWorktree = createMemo(() => base64Encode(props.project.worktree)) const name = createMemo(() => props.project.name || getFilename(props.project.worktree)) const [store, setProjectStore] = globalSync.child(props.project.worktree) @@ -764,20 +798,22 @@ export default function Layout(props: ParentProps) { return props.project.worktree === current || props.project.sandboxes?.includes(current) }) const handleOpenChange = (open: boolean) => { - if (props.mobile) { - if (open) mobileProjects.expand(props.project.worktree) - else mobileProjects.collapse(props.project.worktree) - } else { - if (open) layout.projects.expand(props.project.worktree) - else layout.projects.collapse(props.project.worktree) - } + if (open) layout.projects.expand(props.project.worktree) + else layout.projects.collapse(props.project.worktree) } + const expanded = () => props.mobile || layout.sidebar.opened() + return ( // @ts-ignore
    - - + +
    -
    ) @@ -1104,14 +1165,21 @@ export default function Layout(props: ParentProps) { class="shrink-0 h-8 flex items-center justify-start px-2 w-full" onClick={() => layout.mobileSidebar.hide()} > - +
    -
    {props.children}
    +
    + +
    + + {props.children} + +
    +
    diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 853d3a894ce..ffa7a6b7ebe 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -32,7 +32,7 @@ import { DialogSelectModel } from "@/components/dialog-select-model" import { DialogSelectMcp } from "@/components/dialog-select-mcp" import { useCommand } from "@/context/command" import { useNavigate, useParams } from "@solidjs/router" -import { UserMessage } from "@opencode-ai/sdk/v2" +import { Part, UserMessage, ToolPart } from "@opencode-ai/sdk/v2" import type { FileDiff } from "@opencode-ai/sdk/v2/client" import { useSDK } from "@/context/sdk" import { usePrompt } from "@/context/prompt" @@ -49,6 +49,8 @@ import { NewSessionView, } from "@/components/session" import { usePlatform } from "@/context/platform" +import { useKeyboardVisibility } from "@/hooks/use-keyboard-visibility" +import { AskQuestionWizard, type AskQuestionQuestion, type AskQuestionAnswer } from "@/components/askquestion-wizard" import { same } from "@/utils/same" type DiffStyle = "unified" | "split" @@ -158,6 +160,10 @@ export default function Page() { const sdk = useSDK() const prompt = usePrompt() const permission = usePermission() + + // Initialize keyboard visibility tracking for mobile terminal support + useKeyboardVisibility() + const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey())) const view = createMemo(() => layout.view(sessionKey())) @@ -232,6 +238,106 @@ export default function Page() { }, emptyUserMessages) const lastUserMessage = createMemo(() => visibleUserMessages().at(-1)) + // Detect pending askquestion tools from synced message parts (mirrors TUI logic) + const pendingAskQuestion = createMemo(() => { + if (!params.id) return null + const sessionMessages = sync.data.message[params.id] ?? [] + + const getMetadata = (toolPart: ToolPart) => { + const stateMetadata = (toolPart.state as { metadata?: unknown }).metadata as + | { status?: string; questions?: AskQuestionQuestion[] } + | undefined + const partMetadata = toolPart.metadata as + | { status?: string; questions?: AskQuestionQuestion[] } + | undefined + return stateMetadata ?? partMetadata + } + + const findInParts = (parts: Part[]) => { + for (const part of [...parts].reverse()) { + if (part.type !== "tool") continue + const toolPart = part as ToolPart + + if (toolPart.tool !== "askquestion") continue + if (!toolPart.callID) continue + if (toolPart.state.status !== "running") continue + + const metadata = getMetadata(toolPart) + if (metadata?.status && metadata.status !== "waiting") continue + + const inputQuestions = (toolPart.state.input as { questions?: AskQuestionQuestion[] }).questions + const questions = (metadata?.questions ?? inputQuestions) as AskQuestionQuestion[] | undefined + if (!questions || questions.length === 0) continue + + return { + callID: toolPart.callID, + messageID: toolPart.messageID, + questions, + } + } + return null + } + + // Search backwards for the most recent pending question + for (const message of [...sessionMessages].reverse()) { + const parts = sync.data.part[message.id] ?? [] + const pending = findInParts(parts) + if (pending) return pending + } + + // Fallback: scan all parts in case message list is delayed/out of order + let latest: { pending: { callID: string; messageID: string; questions: AskQuestionQuestion[] }; time: number } | null = null + for (const parts of Object.values(sync.data.part)) { + for (const part of parts) { + if (part.type !== "tool") continue + const toolPart = part as ToolPart + if (toolPart.tool !== "askquestion") continue + if (toolPart.sessionID !== params.id) continue + if (!toolPart.callID) continue + if (toolPart.state.status !== "running") continue + + const metadata = getMetadata(toolPart) + if (metadata?.status && metadata.status !== "waiting") continue + + const inputQuestions = (toolPart.state.input as { questions?: AskQuestionQuestion[] }).questions + const questions = (metadata?.questions ?? inputQuestions) as AskQuestionQuestion[] | undefined + if (!questions || questions.length === 0) continue + + const time = (toolPart.state as { time?: { start?: number } }).time?.start ?? 0 + const pending = { + callID: toolPart.callID, + messageID: toolPart.messageID, + questions, + } + if (!latest || time > latest.time) { + latest = { pending, time } + } + } + } + + return latest?.pending ?? null + }) + + // Handlers for AskQuestion wizard + const handleAskQuestionSubmit = async (answers: AskQuestionAnswer[]) => { + const pending = pendingAskQuestion() + if (!pending || !params.id) return + await sdk.client.askquestion.respond({ + callID: pending.callID, + sessionID: params.id, + answers, + }) + } + + const handleAskQuestionCancel = async () => { + const pending = pendingAskQuestion() + if (!pending || !params.id) return + await sdk.client.askquestion.cancel({ + callID: pending.callID, + sessionID: params.id, + }) + } + createEffect( on( () => lastUserMessage()?.id, @@ -853,7 +959,7 @@ export default function Page() { if (isDesktop()) scheduleScrollSpy(e.currentTarget) }} onClick={autoScroll.handleInteraction} - class="relative min-w-0 w-full h-full overflow-y-auto no-scrollbar" + class="session-scroll-container relative min-w-0 w-full h-full overflow-y-auto no-scrollbar" >
    (promptDock = el)} - class="absolute inset-x-0 bottom-0 pt-12 pb-4 md:pb-8 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" + data-component="prompt-dock" + class="absolute inset-x-0 bottom-0 pt-12 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" + style={{ "padding-bottom": "max(1.5rem, env(safe-area-inset-bottom, 0px))" }} >
    - { - inputRef = el - }} - newSessionWorktree={newSessionWorktree()} - onNewSessionWorktreeReset={() => setStore("newSessionWorktree", "main")} - /> + + {(pending) => ( + + )} + + + { + inputRef = el + }} + newSessionWorktree={newSessionWorktree()} + onNewSessionWorktreeReset={() => setStore("newSessionWorktree", "main")} + /> +
    diff --git a/packages/app/src/theme/apply-theme.ts b/packages/app/src/theme/apply-theme.ts new file mode 100644 index 00000000000..27d8fdaf723 --- /dev/null +++ b/packages/app/src/theme/apply-theme.ts @@ -0,0 +1,76 @@ +import { CLI_THEME_IDS, applyCliTheme, clearTerminalTheme, clearUiTheme } from "@/theme/terminal-themes" + +export const DEFAULT_THEME_ID = "nightowl" + +const BASE_THEMES = [ + { id: DEFAULT_THEME_ID, name: "Night Owl" }, + { id: "opencode", name: "OpenCode" }, + { id: "oc-2-paper", name: "Paper" }, +] + +const baseThemeIds = new Set(BASE_THEMES.map((t) => t.id)) + +const CLI_THEMES = CLI_THEME_IDS.filter((id) => !baseThemeIds.has(id)).map((id) => ({ + id, + name: formatThemeName(id), +})) + +export const THEMES = [...BASE_THEMES, ...CLI_THEMES] + +export type Theme = (typeof THEMES)[number] + +function normalizeThemeId(id: string): string { + if (id === "default") return DEFAULT_THEME_ID + return id +} + +export function formatThemeName(id: string): string { + return id + .replace(/[-_]/g, " ") + .split(" ") + .map((word) => (word ? `${word[0]?.toUpperCase() ?? ""}${word.slice(1)}` : "")) + .join(" ") +} + +export function getThemeById(id: string): Theme { + const normalized = normalizeThemeId(id) + return THEMES.find((t) => t.id === normalized) ?? BASE_THEMES[0] +} + +const OPENCODE_THEME_STORAGE_KEYS = [ + "opencode-theme-id", + "opencode-color-scheme", + "opencode-theme-css-light", + "opencode-theme-css-dark", +] + +function clearOpencodeTheme() { + if (typeof document === "undefined") return + for (const key of OPENCODE_THEME_STORAGE_KEYS) { + localStorage.removeItem(key) + } + document.getElementById("oc-theme")?.remove() + document.getElementById("oc-theme-preload")?.remove() + document.documentElement.removeAttribute("data-color-scheme") +} + +export function applyTheme(themeId: string) { + const theme = getThemeById(themeId) + clearOpencodeTheme() + + // "opencode" theme uses the default :root styles (no data-theme attribute) + if (theme.id === "opencode") { + document.documentElement.removeAttribute("data-theme") + } else { + document.documentElement.setAttribute("data-theme", theme.id) + } + + if (baseThemeIds.has(theme.id)) { + clearTerminalTheme() + clearUiTheme() + } else { + applyCliTheme(theme.id) + } + + document.documentElement.dispatchEvent(new CustomEvent("terminal-theme-changed")) +} diff --git a/packages/app/src/theme/terminal-themes.ts b/packages/app/src/theme/terminal-themes.ts new file mode 100644 index 00000000000..bd972c33e7b --- /dev/null +++ b/packages/app/src/theme/terminal-themes.ts @@ -0,0 +1,386 @@ +import type { Component } from "solid-js" + +type Variant = { + dark: string + light: string +} + +type ColorValue = string | Variant + +type CliThemeJson = { + defs?: Record + theme: Record +} + +type TerminalPalette = { + background: string + foreground: string + cursor: string + black: string + red: string + green: string + yellow: string + blue: string + magenta: string + cyan: string + white: string + brightBlack: string + brightRed: string + brightGreen: string + brightYellow: string + brightBlue: string + brightMagenta: string + brightCyan: string + brightWhite: string +} + +const terminalVars: (keyof TerminalPalette)[] = [ + "background", + "foreground", + "cursor", + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", + "brightBlack", + "brightRed", + "brightGreen", + "brightYellow", + "brightBlue", + "brightMagenta", + "brightCyan", + "brightWhite", +] + +import aura from "../../../opencode/src/cli/cmd/tui/context/theme/aura.json" assert { type: "json" } +import ayu from "../../../opencode/src/cli/cmd/tui/context/theme/ayu.json" assert { type: "json" } +import catppuccin from "../../../opencode/src/cli/cmd/tui/context/theme/catppuccin.json" assert { type: "json" } +import catppuccinMacchiato from "../../../opencode/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json" assert { type: "json" } +import cobalt2 from "../../../opencode/src/cli/cmd/tui/context/theme/cobalt2.json" assert { type: "json" } +import dracula from "../../../opencode/src/cli/cmd/tui/context/theme/dracula.json" assert { type: "json" } +import everforest from "../../../opencode/src/cli/cmd/tui/context/theme/everforest.json" assert { type: "json" } +import flexoki from "../../../opencode/src/cli/cmd/tui/context/theme/flexoki.json" assert { type: "json" } +import github from "../../../opencode/src/cli/cmd/tui/context/theme/github.json" assert { type: "json" } +import gruvbox from "../../../opencode/src/cli/cmd/tui/context/theme/gruvbox.json" assert { type: "json" } +import kanagawa from "../../../opencode/src/cli/cmd/tui/context/theme/kanagawa.json" assert { type: "json" } +import material from "../../../opencode/src/cli/cmd/tui/context/theme/material.json" assert { type: "json" } +import matrix from "../../../opencode/src/cli/cmd/tui/context/theme/matrix.json" assert { type: "json" } +import mercury from "../../../opencode/src/cli/cmd/tui/context/theme/mercury.json" assert { type: "json" } +import monokai from "../../../opencode/src/cli/cmd/tui/context/theme/monokai.json" assert { type: "json" } +import nightowl from "../../../opencode/src/cli/cmd/tui/context/theme/nightowl.json" assert { type: "json" } +import nord from "../../../opencode/src/cli/cmd/tui/context/theme/nord.json" assert { type: "json" } +import onedark from "../../../opencode/src/cli/cmd/tui/context/theme/one-dark.json" assert { type: "json" } +import orng from "../../../opencode/src/cli/cmd/tui/context/theme/orng.json" assert { type: "json" } +import palenight from "../../../opencode/src/cli/cmd/tui/context/theme/palenight.json" assert { type: "json" } +import rosepine from "../../../opencode/src/cli/cmd/tui/context/theme/rosepine.json" assert { type: "json" } +import solarized from "../../../opencode/src/cli/cmd/tui/context/theme/solarized.json" assert { type: "json" } +import synthwave84 from "../../../opencode/src/cli/cmd/tui/context/theme/synthwave84.json" assert { type: "json" } +import tokyonight from "../../../opencode/src/cli/cmd/tui/context/theme/tokyonight.json" assert { type: "json" } +import vercel from "../../../opencode/src/cli/cmd/tui/context/theme/vercel.json" assert { type: "json" } +import vesper from "../../../opencode/src/cli/cmd/tui/context/theme/vesper.json" assert { type: "json" } +import zenburn from "../../../opencode/src/cli/cmd/tui/context/theme/zenburn.json" assert { type: "json" } + +const CLI_THEME_MAP: Record = { + aura, + ayu, + catppuccin, + "catppuccin-macchiato": catppuccinMacchiato, + cobalt2, + dracula, + everforest, + flexoki, + github, + gruvbox, + kanagawa, + material, + matrix, + mercury, + monokai, + nightowl, + nord, + "one-dark": onedark, + orng, + palenight, + rosepine, + solarized, + synthwave84, + tokyonight, + vercel, + vesper, + zenburn, +} + +export const CLI_THEME_IDS = Object.keys(CLI_THEME_MAP).sort() + +function hexToRgb(hex: string): [number, number, number] { + const normalized = hex.replace("#", "") + const value = + normalized.length === 3 + ? normalized + .split("") + .map((c) => c + c) + .join("") + : normalized + const num = parseInt(value, 16) + return [(num >> 16) & 255, (num >> 8) & 255, num & 255] +} + +function rgbToHex([r, g, b]: [number, number, number]): string { + const clamp = (v: number) => Math.max(0, Math.min(255, Math.round(v))) + return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b) + .toString(16) + .padStart(2, "0")}` +} + +function adjust(hex: string, amount: number): string { + const [r, g, b] = hexToRgb(hex) + return rgbToHex([r + (255 - r) * amount, g + (255 - g) * amount, b + (255 - b) * amount]) +} + +function darken(hex: string, amount: number): string { + const [r, g, b] = hexToRgb(hex) + return rgbToHex([r * (1 - amount), g * (1 - amount), b * (1 - amount)]) +} + +function luminance(hex: string): number { + const [r, g, b] = hexToRgb(hex).map((v) => v / 255) + return 0.299 * r + 0.587 * g + 0.114 * b +} + +function mix(a: string, b: string, amount: number): string { + const [ar, ag, ab] = hexToRgb(a) + const [br, bg, bb] = hexToRgb(b) + return rgbToHex([ar + (br - ar) * amount, ag + (bg - ag) * amount, ab + (bb - ab) * amount]) +} + +function resolveColor( + value: ColorValue | undefined, + defs: Record, + theme: CliThemeJson, + mode: "dark" | "light", +): string | undefined { + if (!value) return undefined + if (typeof value === "string") { + if (value.startsWith("#")) return value + if (defs[value]) return resolveColor(defs[value], defs, theme, mode) + if (theme.theme[value]) return resolveColor(theme.theme[value], defs, theme, mode) + return value + } + return resolveColor(value[mode], defs, theme, mode) +} + +function toHex(value: string | undefined, fallback: string): string { + if (!value) return fallback + if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(value)) return value + return fallback +} + +function basePalette(id: string): TerminalPalette | undefined { + const theme = CLI_THEME_MAP[id] + if (!theme) return undefined + const defs = theme.defs ?? {} + const mode: "dark" | "light" = "dark" + + const background = toHex(resolveColor(theme.theme.background, defs, theme, mode), "#011627") + const foreground = toHex(resolveColor(theme.theme.text, defs, theme, mode), "#d6deeb") + const cursor = toHex(resolveColor(theme.theme.accent ?? theme.theme.primary, defs, theme, mode), foreground) + + const paletteBase = { + red: toHex(resolveColor(theme.theme.error, defs, theme, mode), "#ef5350"), + green: toHex(resolveColor(theme.theme.success, defs, theme, mode), "#c5e478"), + yellow: toHex(resolveColor(theme.theme.warning, defs, theme, mode), "#ecc48d"), + blue: toHex(resolveColor(theme.theme.primary, defs, theme, mode), "#82aaff"), + magenta: toHex(resolveColor(theme.theme.accent ?? theme.theme.secondary, defs, theme, mode), "#c792ea"), + cyan: toHex(resolveColor(theme.theme.info, defs, theme, mode), "#7fdbca"), + } + + const isDark = luminance(background) < 0.5 + const bright = (hex: string) => (isDark ? adjust(hex, 0.25) : darken(hex, 0.25)) + const brightFromBg = isDark ? adjust(background, 0.35) : darken(background, 0.35) + const brightFromFg = isDark ? adjust(foreground, 0.2) : darken(foreground, 0.2) + + return { + background, + foreground, + cursor, + black: background, + red: paletteBase.red, + green: paletteBase.green, + yellow: paletteBase.yellow, + blue: paletteBase.blue, + magenta: paletteBase.magenta, + cyan: paletteBase.cyan, + white: foreground, + brightBlack: brightFromBg, + brightRed: bright(paletteBase.red), + brightGreen: bright(paletteBase.green), + brightYellow: bright(paletteBase.yellow), + brightBlue: bright(paletteBase.blue), + brightMagenta: bright(paletteBase.magenta), + brightCyan: bright(paletteBase.cyan), + brightWhite: brightFromFg, + } +} + +export function resolveTerminalPalette(id: string): TerminalPalette | undefined { + return basePalette(id) +} + +function applyUiTheme(palette: TerminalPalette) { + if (typeof document === "undefined") return + + const rootStyle = document.documentElement.style + const isDark = luminance(palette.background) < 0.5 + const bg = palette.background + const fg = palette.foreground + const weakBg = isDark ? adjust(bg, 0.08) : darken(bg, 0.08) + const strongBg = isDark ? adjust(bg, 0.15) : darken(bg, 0.12) + const strongerBg = isDark ? adjust(bg, 0.06) : darken(bg, 0.04) + const surface = isDark ? adjust(bg, 0.1) : darken(bg, 0.1) + const surfaceHover = isDark ? adjust(bg, 0.18) : darken(bg, 0.15) + const surfaceActive = isDark ? adjust(bg, 0.22) : darken(bg, 0.18) + const floatBase = isDark ? adjust(bg, 0.12) : darken(bg, 0.12) + const textWeak = mix(fg, bg, isDark ? 0.4 : 0.35) + const textWeaker = mix(fg, bg, isDark ? 0.5 : 0.45) + const iconWeak = mix(fg, bg, isDark ? 0.55 : 0.5) + const border = mix(fg, bg, isDark ? 0.75 : 0.8) + const borderStrong = mix(fg, bg, isDark ? 0.65 : 0.7) + const set = (name: string, value: string) => rootStyle.setProperty(name, value) + + set("color-scheme", isDark ? "dark" : "light") + set("--background-base", bg) + set("--background-weak", weakBg) + set("--background-strong", strongBg) + set("--background-stronger", strongerBg) + set("--surface-base", surface) + set("--surface-base-hover", surfaceHover) + set("--surface-base-active", surfaceActive) + set("--surface-raised-base", surface) + set("--surface-raised-base-hover", surfaceHover) + set("--surface-raised-base-active", surfaceActive) + set("--surface-raised-stronger-non-alpha", strongBg) + set("--surface-weak", weakBg) + set("--surface-strong", strongBg) + set("--surface-float-base", floatBase) + set("--text-base", fg) + set("--text-strong", fg) + set("--text-weak", textWeak) + set("--text-weaker", textWeaker) + set("--icon-base", textWeak) + set("--icon-weak-base", iconWeak) + set("--icon-strong-base", fg) + set("--border-base", border) + set("--border-weak-base", border) + set("--border-weak-hover", border) + set("--border-weak-active", borderStrong) + set("--border-strong-base", borderStrong) + set("--border-strong-hover", borderStrong) + set("--border-strong-active", borderStrong) + set("--border-strong-selected", borderStrong) + set("--border-selected", borderStrong) + set("--border-weak-selected", `${borderStrong}4D`) // 30% opacity + set("--border-interactive-base", borderStrong) + set("--border-interactive-hover", borderStrong) + set("--border-interactive-active", borderStrong) + set("--border-interactive-selected", borderStrong) + set("--surface-interactive-base", palette.blue) + set("--text-interactive-base", palette.blue) + set("--surface-brand-base", palette.blue) + set("--button-secondary-base", surface) +} + +const uiVars = [ + "color-scheme", + "--background-base", + "--background-weak", + "--background-strong", + "--background-stronger", + "--surface-base", + "--surface-base-hover", + "--surface-base-active", + "--surface-raised-base", + "--surface-raised-base-hover", + "--surface-raised-base-active", + "--surface-raised-stronger-non-alpha", + "--surface-weak", + "--surface-strong", + "--surface-float-base", + "--text-base", + "--text-strong", + "--text-weak", + "--text-weaker", + "--icon-base", + "--icon-weak-base", + "--icon-strong-base", + "--border-base", + "--border-weak-base", + "--border-weak-hover", + "--border-weak-active", + "--border-strong-base", + "--border-strong-hover", + "--border-strong-active", + "--border-strong-selected", + "--border-selected", + "--border-weak-selected", + "--border-interactive-base", + "--border-interactive-hover", + "--border-interactive-active", + "--border-interactive-selected", + "--surface-interactive-base", + "--text-interactive-base", + "--surface-brand-base", + "--button-secondary-base", +] + +export function clearUiTheme() { + if (typeof document === "undefined") return + const rootStyle = document.documentElement.style + for (const key of uiVars) { + rootStyle.removeProperty(key) + } +} + +export function applyCliTheme(id: string) { + if (typeof document === "undefined") return + const palette = resolveTerminalPalette(id) + if (!palette) { + clearTerminalTheme() + clearUiTheme() + return + } + applyTerminalTheme(id) + applyUiTheme(palette) + document.documentElement.setAttribute("data-theme", id) +} + +export function applyTerminalTheme(id: string) { + if (typeof document === "undefined") return + + const palette = resolveTerminalPalette(id) + if (!palette) { + clearTerminalTheme() + return + } + + const rootStyle = document.documentElement.style + for (const key of terminalVars) { + rootStyle.setProperty(`--terminal-${kebab(key)}`, palette[key]) + } +} + +export function clearTerminalTheme() { + if (typeof document === "undefined") return + + const rootStyle = document.documentElement.style + for (const key of terminalVars) { + rootStyle.removeProperty(`--terminal-${kebab(key)}`) + } +} + +function kebab(value: string): string { + return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`) +} diff --git a/packages/app/src/utils/hosted.ts b/packages/app/src/utils/hosted.ts new file mode 100644 index 00000000000..94c4c9b9c91 --- /dev/null +++ b/packages/app/src/utils/hosted.ts @@ -0,0 +1,25 @@ +/** + * Checks if the app is running in a hosted environment (app.shuv.ai or app.opencode.ai). + * In hosted environments, users need to configure their server connection. + */ +export function isHostedEnvironment(): boolean { + if (typeof window === "undefined") return false + return location.hostname.includes("opencode.ai") || location.hostname.includes("shuv.ai") +} + +/** + * Checks if a ?url= query parameter was provided in the URL. + * This indicates the user is trying to connect to a specific server. + */ +export function hasUrlQueryParam(): boolean { + if (typeof window === "undefined") return false + return new URLSearchParams(document.location.search).has("url") +} + +/** + * Gets the ?url= query parameter value if present. + */ +export function getUrlQueryParam(): string | null { + if (typeof window === "undefined") return null + return new URLSearchParams(document.location.search).get("url") +} diff --git a/packages/app/test/hosted.test.ts b/packages/app/test/hosted.test.ts new file mode 100644 index 00000000000..09d1620416e --- /dev/null +++ b/packages/app/test/hosted.test.ts @@ -0,0 +1,132 @@ +import { describe, expect, test, beforeEach, afterEach } from "bun:test" + +// Note: These tests require the happy-dom environment set up via bunfig.toml + +describe("hosted.ts utilities", () => { + let originalHostname: string + let originalSearch: string + + beforeEach(() => { + originalHostname = window.location.hostname + originalSearch = window.location.search + }) + + afterEach(() => { + // Reset location properties (happy-dom allows this) + Object.defineProperty(window.location, "hostname", { + value: originalHostname, + writable: true, + }) + Object.defineProperty(window.location, "search", { + value: originalSearch, + writable: true, + }) + }) + + describe("isHostedEnvironment", () => { + test("returns true for opencode.ai domains", async () => { + Object.defineProperty(window.location, "hostname", { + value: "app.opencode.ai", + writable: true, + }) + + // Dynamic import to get fresh evaluation + const { isHostedEnvironment } = await import("../src/utils/hosted") + expect(isHostedEnvironment()).toBe(true) + }) + + test("returns true for shuv.ai domains", async () => { + Object.defineProperty(window.location, "hostname", { + value: "app.shuv.ai", + writable: true, + }) + + const { isHostedEnvironment } = await import("../src/utils/hosted") + expect(isHostedEnvironment()).toBe(true) + }) + + test("returns false for localhost", async () => { + Object.defineProperty(window.location, "hostname", { + value: "localhost", + writable: true, + }) + + const { isHostedEnvironment } = await import("../src/utils/hosted") + expect(isHostedEnvironment()).toBe(false) + }) + + test("returns false for other domains", async () => { + Object.defineProperty(window.location, "hostname", { + value: "example.com", + writable: true, + }) + + const { isHostedEnvironment } = await import("../src/utils/hosted") + expect(isHostedEnvironment()).toBe(false) + }) + }) + + describe("hasUrlQueryParam", () => { + test("returns true when ?url= parameter exists", async () => { + Object.defineProperty(window.location, "search", { + value: "?url=http://localhost:4096", + writable: true, + }) + + const { hasUrlQueryParam } = await import("../src/utils/hosted") + expect(hasUrlQueryParam()).toBe(true) + }) + + test("returns false when no ?url= parameter", async () => { + Object.defineProperty(window.location, "search", { + value: "", + writable: true, + }) + + const { hasUrlQueryParam } = await import("../src/utils/hosted") + expect(hasUrlQueryParam()).toBe(false) + }) + + test("returns false when other parameters exist but not ?url=", async () => { + Object.defineProperty(window.location, "search", { + value: "?foo=bar&baz=qux", + writable: true, + }) + + const { hasUrlQueryParam } = await import("../src/utils/hosted") + expect(hasUrlQueryParam()).toBe(false) + }) + }) + + describe("getUrlQueryParam", () => { + test("returns the URL value when present", async () => { + Object.defineProperty(window.location, "search", { + value: "?url=http://localhost:4096", + writable: true, + }) + + const { getUrlQueryParam } = await import("../src/utils/hosted") + expect(getUrlQueryParam()).toBe("http://localhost:4096") + }) + + test("returns null when not present", async () => { + Object.defineProperty(window.location, "search", { + value: "", + writable: true, + }) + + const { getUrlQueryParam } = await import("../src/utils/hosted") + expect(getUrlQueryParam()).toBeNull() + }) + + test("handles URL-encoded values", async () => { + Object.defineProperty(window.location, "search", { + value: "?url=https%3A%2F%2Fmy-server.example.com%3A8080", + writable: true, + }) + + const { getUrlQueryParam } = await import("../src/utils/hosted") + expect(getUrlQueryParam()).toBe("https://my-server.example.com:8080") + }) + }) +}) diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts index 6a29ae6345e..59c4f0e1239 100644 --- a/packages/app/vite.config.ts +++ b/packages/app/vite.config.ts @@ -1,12 +1,158 @@ import { defineConfig } from "vite" +import { readFileSync } from "fs" +import { sep } from "path" +import { VitePWA } from "vite-plugin-pwa" import desktopPlugin from "./vite" +import { execSync } from "child_process" + +const pkg = JSON.parse(readFileSync("./package.json", "utf-8")) +const commitHash = + process.env.OPENCODE_COMMIT_HASH || + (() => { + try { + return execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim() + } catch { + return "unknown" + } + })() +const apiPort = process.env.VITE_OPENCODE_SERVER_PORT ?? "4096" +const apiTarget = `http://127.0.0.1:${apiPort}` +const repoRoot = + process.env.OPENCODE_REPO_ROOT || + (() => { + try { + return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim() + } catch { + return process.cwd() + } + })() +const reposRoot = (() => { + const parts = repoRoot.split(sep) + const reposIndex = parts.lastIndexOf("repos") + return reposIndex === -1 ? repoRoot : parts.slice(0, reposIndex + 1).join(sep) +})() +const devOrigin = process.env.VITE_DEV_ORIGIN +const devHmrHost = process.env.VITE_DEV_HMR_HOST +const devHmrPort = process.env.VITE_DEV_HMR_PORT + +// All API route prefixes from the opencode server +const apiRoutes = [ + "/agent", + "/auth", + "/command", + "/config", + "/doc", + "/event", + "/experimental", + "/file", + "/find", + "/formatter", + "/global", + "/instance", + "/log", + "/lsp", + "/mcp", + "/path", + "/project", + "/provider", + "/pty", + "/session", + "/tui", + "/vcs", +] + export default defineConfig({ - plugins: [desktopPlugin] as any, + plugins: [ + desktopPlugin, + VitePWA({ + registerType: "autoUpdate", + includeAssets: ["favicon.ico", "favicon.svg", "favicon-96x96.png", "apple-touch-icon.png"], + manifest: false, // Use the existing site.webmanifest + workbox: { + globPatterns: ["**/*.{js,css,html,ico,png,svg,woff2}"], + maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5 MiB - allow larger JS bundles + // Don't cache API routes + navigateFallbackDenylist: apiRoutes.map((route) => new RegExp(`^${route}`)), + runtimeCaching: [ + { + urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, + handler: "CacheFirst", + options: { + cacheName: "google-fonts-cache", + expiration: { + maxEntries: 10, + maxAgeSeconds: 60 * 60 * 24 * 365, // 1 year + }, + cacheableResponse: { + statuses: [0, 200], + }, + }, + }, + { + urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i, + handler: "CacheFirst", + options: { + cacheName: "gstatic-fonts-cache", + expiration: { + maxEntries: 10, + maxAgeSeconds: 60 * 60 * 24 * 365, // 1 year + }, + cacheableResponse: { + statuses: [0, 200], + }, + }, + }, + { + urlPattern: /^https:\/\/cdn\.jsdelivr\.net\/.*/i, + handler: "CacheFirst", + options: { + cacheName: "jsdelivr-cache", + expiration: { + maxEntries: 10, + maxAgeSeconds: 60 * 60 * 24 * 365, // 1 year + }, + cacheableResponse: { + statuses: [0, 200], + }, + }, + }, + ], + }, + devOptions: { + enabled: true, // Enable PWA in development mode for testing + }, + }), + ] as any, + define: { + __APP_VERSION__: JSON.stringify(pkg.version), + __COMMIT_HASH__: JSON.stringify(commitHash), + }, server: { host: "0.0.0.0", allowedHosts: true, port: 3000, + origin: devOrigin, + hmr: + devHmrHost || devHmrPort + ? { + host: devHmrHost, + clientPort: devHmrPort ? Number(devHmrPort) : undefined, + } + : undefined, + fs: { + allow: [repoRoot, reposRoot], + }, + proxy: Object.fromEntries( + apiRoutes.map((route) => [ + route, + { + target: apiTarget, + changeOrigin: true, + ws: true, + }, + ]), + ), }, build: { target: "esnext", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index c65bba4b1aa..194d44f47e9 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.1.4", + "version": "1.1.4-1", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index c22276bf055..f3f5f8df38a 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.1.4", + "version": "1.1.4-1", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index cc433d64785..7b8d20cf1c4 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.1.4", + "version": "1.1.4-1", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index a38da04aec7..8516f1354c7 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.1.4", + "version": "1.1.4-1", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/.env.development b/packages/desktop/.env.development new file mode 100644 index 00000000000..db6a8d1b9f3 --- /dev/null +++ b/packages/desktop/.env.development @@ -0,0 +1,3 @@ +# Development environment variables +# This port must match the --port argument when running `bun run dev serve --port 4096` +VITE_OPENCODE_SERVER_PORT=4096 diff --git a/packages/desktop/.gitignore b/packages/desktop/.gitignore index a547bf36d8d..5440503b1a1 100644 --- a/packages/desktop/.gitignore +++ b/packages/desktop/.gitignore @@ -1,24 +1,2 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +src/assets/theme.css +dev-dist/ diff --git a/packages/desktop/README.md b/packages/desktop/README.md index ebaf4882231..90618540e15 100644 --- a/packages/desktop/README.md +++ b/packages/desktop/README.md @@ -1,32 +1,21 @@ -# OpenCode Desktop +# Shuvcode Desktop (Tauri) -Native OpenCode desktop app, built with Tauri v2. +This package bundles the Shuvcode desktop app and ships the CLI sidecar. ## Development -From the repo root: - -```bash -bun install -bun run --cwd packages/desktop tauri dev -``` - -This starts the Vite 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 -``` +1. Build the sidecar CLI for your target: + `bun run predev` +2. Start the desktop app: + `bun run tauri dev` ## Build -To create a production `dist/` and build the native app bundle: - -```bash -bun run --cwd packages/desktop tauri build -``` +1. Ensure the sidecar is present: + `bun run predev` +2. Build the Tauri bundles: + `bun run tauri build` -## Prerequisites +## Recommended IDE Setup -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. +- VS Code + Tauri + rust-analyzer diff --git a/packages/desktop/index.html b/packages/desktop/index.html index f93e972940e..e2a8625689e 100644 --- a/packages/desktop/index.html +++ b/packages/desktop/index.html @@ -1,52 +1,42 @@ - + - - OpenCode + + shuvcode - - + + + + + + + - - -
    +
    diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 3370ad36389..eb7895486c2 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { - "name": "@opencode-ai/desktop", + "name": "@shuvcode/desktop", "private": true, - "version": "1.1.4", + "version": "1.1.4-1", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/desktop/scripts/copy-bundles.ts b/packages/desktop/scripts/copy-bundles.ts index 3fde1c19010..8f16f967a70 100644 --- a/packages/desktop/scripts/copy-bundles.ts +++ b/packages/desktop/scripts/copy-bundles.ts @@ -9,4 +9,4 @@ const BUNDLE_DIR = `src-tauri/target/${RUST_TARGET}/release/bundle` const BUNDLES_OUT_DIR = path.join(process.cwd(), `src-tauri/target/bundles`) await $`mkdir -p ${BUNDLES_OUT_DIR}` -await $`cp -r ${BUNDLE_DIR}/*/OpenCode* ${BUNDLES_OUT_DIR}` +await $`cp -r ${BUNDLE_DIR}/*/Shuvcode* ${BUNDLES_OUT_DIR}` diff --git a/packages/desktop/scripts/predev.ts b/packages/desktop/scripts/predev.ts index 3d0cd5e92b1..d1db0bbc941 100644 --- a/packages/desktop/scripts/predev.ts +++ b/packages/desktop/scripts/predev.ts @@ -6,7 +6,7 @@ const RUST_TARGET = Bun.env.TAURI_ENV_TARGET_TRIPLE const sidecarConfig = getCurrentSidecar(RUST_TARGET) -const binaryPath = `../opencode/dist/${sidecarConfig.ocBinary}/bin/opencode${process.platform === "win32" ? ".exe" : ""}` +const binaryPath = `../opencode/dist/${sidecarConfig.ocBinary}/bin/shuvcode${process.platform === "win32" ? ".exe" : ""}` await $`cd ../opencode && bun run build --single` diff --git a/packages/desktop/scripts/prepare.ts b/packages/desktop/scripts/prepare.ts index 495a0baea42..fcff0da4b79 100755 --- a/packages/desktop/scripts/prepare.ts +++ b/packages/desktop/scripts/prepare.ts @@ -5,11 +5,11 @@ import { copyBinaryToSidecarFolder, getCurrentSidecar } from "./utils" const sidecarConfig = getCurrentSidecar() -const dir = "src-tauri/target/opencode-binaries" +const dir = "src-tauri/target/shuvcode-binaries" await $`mkdir -p ${dir}` -await $`gh run download ${Bun.env.GITHUB_RUN_ID} -n opencode-cli`.cwd(dir) +await $`gh run download ${Bun.env.GITHUB_RUN_ID} -n shuvcode-cli`.cwd(dir) await copyBinaryToSidecarFolder( - `${dir}/${sidecarConfig.ocBinary}/bin/opencode${process.platform === "win32" ? ".exe" : ""}`, + `${dir}/${sidecarConfig.ocBinary}/bin/shuvcode${process.platform === "win32" ? ".exe" : ""}`, ) diff --git a/packages/desktop/scripts/utils.ts b/packages/desktop/scripts/utils.ts index 885d0afce89..20868430488 100644 --- a/packages/desktop/scripts/utils.ts +++ b/packages/desktop/scripts/utils.ts @@ -3,27 +3,27 @@ import { $ } from "bun" export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; assetExt: string }> = [ { rustTarget: "aarch64-apple-darwin", - ocBinary: "opencode-darwin-arm64", + ocBinary: "shuvcode-darwin-arm64", assetExt: "zip", }, { rustTarget: "x86_64-apple-darwin", - ocBinary: "opencode-darwin-x64", + ocBinary: "shuvcode-darwin-x64", assetExt: "zip", }, { rustTarget: "x86_64-pc-windows-msvc", - ocBinary: "opencode-windows-x64", + ocBinary: "shuvcode-windows-x64", assetExt: "zip", }, { rustTarget: "x86_64-unknown-linux-gnu", - ocBinary: "opencode-linux-x64", + ocBinary: "shuvcode-linux-x64", assetExt: "tar.gz", }, { rustTarget: "aarch64-unknown-linux-gnu", - ocBinary: "opencode-linux-arm64", + ocBinary: "shuvcode-linux-arm64", assetExt: "tar.gz", }, ] @@ -41,7 +41,7 @@ export function getCurrentSidecar(target = RUST_TARGET) { export async function copyBinaryToSidecarFolder(source: string, target = RUST_TARGET) { await $`mkdir -p src-tauri/sidecars` - const dest = `src-tauri/sidecars/opencode-cli-${target}${process.platform === "win32" ? ".exe" : ""}` + const dest = `src-tauri/sidecars/shuvcode-cli-${target}${process.platform === "win32" ? ".exe" : ""}` await $`cp ${source} ${dest}` console.log(`Copied ${source} to ${dest}`) diff --git a/packages/desktop/src-tauri/Cargo.toml b/packages/desktop/src-tauri/Cargo.toml index 63aafe28010..00a75995371 100644 --- a/packages/desktop/src-tauri/Cargo.toml +++ b/packages/desktop/src-tauri/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "opencode-desktop" +name = "shuvcode-desktop" version = "0.0.0" description = "The open source AI coding agent" authors = ["Anomaly Innovations"] @@ -11,7 +11,7 @@ edition = "2021" # The `_lib` suffix may seem redundant but it is necessary # to make the lib name unique and wouldn't conflict with the bin name. # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "opencode_lib" +name = "shuvcode_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] diff --git a/packages/desktop/src-tauri/src/lib.rs b/packages/desktop/src-tauri/src/lib.rs index 5d1610fa3e6..4f1bacec1ea 100644 --- a/packages/desktop/src-tauri/src/lib.rs +++ b/packages/desktop/src-tauri/src/lib.rs @@ -80,8 +80,10 @@ async fn get_logs(app: AppHandle) -> Result { } fn get_sidecar_port() -> u32 { - option_env!("OPENCODE_PORT") + option_env!("SHUVCODE_PORT") .map(|s| s.to_string()) + .or_else(|| option_env!("OPENCODE_PORT").map(|s| s.to_string())) + .or_else(|| std::env::var("SHUVCODE_PORT").ok()) .or_else(|| std::env::var("OPENCODE_PORT").ok()) .and_then(|port_str| port_str.parse().ok()) .unwrap_or_else(|| { @@ -109,14 +111,16 @@ fn spawn_sidecar(app: &AppHandle, port: u32) -> CommandChild { #[cfg(target_os = "windows")] let (mut rx, child) = app .shell() - .sidecar("opencode-cli") + .sidecar("shuvcode-cli") .unwrap() + .env("SHUVCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") + .env("SHUVCODE_CLIENT", "desktop") .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") .env("OPENCODE_CLIENT", "desktop") .env("XDG_STATE_HOME", &state_dir) .args(["serve", &format!("--port={port}")]) .spawn() - .expect("Failed to spawn opencode"); + .expect("Failed to spawn shuvcode"); #[cfg(not(target_os = "windows"))] let (mut rx, child) = { @@ -124,6 +128,8 @@ fn spawn_sidecar(app: &AppHandle, port: u32) -> CommandChild { let shell = get_user_shell(); app.shell() .command(&shell) + .env("SHUVCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") + .env("SHUVCODE_CLIENT", "desktop") .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") .env("OPENCODE_CLIENT", "desktop") .env("XDG_STATE_HOME", &state_dir) @@ -133,7 +139,7 @@ fn spawn_sidecar(app: &AppHandle, port: u32) -> CommandChild { &format!("{} serve --port={}", sidecar.display(), port), ]) .spawn() - .expect("Failed to spawn opencode") + .expect("Failed to spawn shuvcode") }; tauri::async_runtime::spawn(async move { @@ -233,11 +239,12 @@ pub fn run() { loop { if timestamp.elapsed() > Duration::from_secs(7) { let res = app.dialog() - .message("Failed to spawn OpenCode Server. Copy logs using the button below and send them to the team for assistance.") + .message("Failed to spawn Shuvcode Server. Copy logs using the button below and send them to the team for assistance.") .title("Startup Failed") .buttons(MessageDialogButtons::OkCancelCustom("Copy Logs And Exit".to_string(), "Exit".to_string())) .blocking_show_with_result(); + if matches!(&res, MessageDialogResult::Custom(name) if name == "Copy Logs And Exit") { match copy_logs_to_clipboard(app.clone()).await { Ok(()) => println!("Logs copied to clipboard successfully"), @@ -272,20 +279,21 @@ pub fn run() { .map(|m| m.size().to_logical(m.scale_factor())) .unwrap_or(LogicalSize::new(1920, 1080)); - let mut window_builder = - WebviewWindow::builder(&app, "main", WebviewUrl::App("/".into())) - .title("OpenCode") - .inner_size(size.width as f64, size.height as f64) - .decorations(true) - .zoom_hotkeys_enabled(true) - .disable_drag_drop_handler() - .initialization_script(format!( - r#" - window.__OPENCODE__ ??= {{}}; - window.__OPENCODE__.updaterEnabled = {updater_enabled}; - window.__OPENCODE__.port = {port}; - "# - )); + let mut window_builder = + WebviewWindow::builder(&app, "main", WebviewUrl::App("/".into())) + .title("Shuvcode") + .inner_size(size.width as f64, size.height as f64) + .decorations(true) + .zoom_hotkeys_enabled(true) + .disable_drag_drop_handler() + .initialization_script(format!( + r#" + window.__SHUVCODE__ ??= {{}}; + window.__SHUVCODE__.updaterEnabled = {updater_enabled}; + window.__SHUVCODE__.port = {port}; + window.__OPENCODE__ ??= window.__SHUVCODE__; + "# + )); #[cfg(target_os = "macos")] { diff --git a/packages/desktop/src-tauri/src/main.rs b/packages/desktop/src-tauri/src/main.rs index b215f8c55a9..db6580ec156 100644 --- a/packages/desktop/src-tauri/src/main.rs +++ b/packages/desktop/src-tauri/src/main.rs @@ -25,11 +25,12 @@ fn configure_display_backend() -> Option { // Allow users to explicitly keep Wayland if they know their setup is stable. let allow_wayland = matches!( - env::var("OC_ALLOW_WAYLAND"), + env::var("SHUVCODE_ALLOW_WAYLAND") + .or_else(|_| env::var("OC_ALLOW_WAYLAND")), Ok(v) if matches!(v.to_ascii_lowercase().as_str(), "1" | "true" | "yes") ); if allow_wayland { - return Some("Wayland session detected; respecting OC_ALLOW_WAYLAND=1".into()); + return Some("Wayland session detected; respecting SHUVCODE_ALLOW_WAYLAND=1".into()); } // Prefer XWayland when available to avoid Wayland protocol errors seen during startup. @@ -39,7 +40,7 @@ fn configure_display_backend() -> Option { set_env_if_absent("WEBKIT_DISABLE_DMABUF_RENDERER", "1"); return Some( "Wayland session detected; forcing X11 backend to avoid compositor protocol errors. \ - Set OC_ALLOW_WAYLAND=1 to keep native Wayland." + Set SHUVCODE_ALLOW_WAYLAND=1 to keep native Wayland." .into(), ); } @@ -59,5 +60,5 @@ fn main() { } } - opencode_lib::run() + shuvcode_lib::run() } diff --git a/packages/desktop/src-tauri/tauri.conf.json b/packages/desktop/src-tauri/tauri.conf.json index bcb067a3207..1651718597a 100644 --- a/packages/desktop/src-tauri/tauri.conf.json +++ b/packages/desktop/src-tauri/tauri.conf.json @@ -1,8 +1,8 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "OpenCode Dev", - "identifier": "ai.opencode.desktop.dev", - "mainBinaryName": "OpenCode", + "productName": "Shuvcode Dev", + "identifier": "dev.shuvcode.desktop.dev", + "mainBinaryName": "Shuvcode", "version": "../package.json", "build": { "beforeDevCommand": "bun run dev", @@ -27,7 +27,7 @@ ], "active": true, "targets": ["deb", "rpm", "dmg", "nsis", "app", "appimage"], - "externalBin": ["sidecars/opencode-cli"], + "externalBin": ["sidecars/shuvcode-cli"], "macOS": { "entitlements": "./entitlements.plist" }, diff --git a/packages/desktop/src-tauri/tauri.prod.conf.json b/packages/desktop/src-tauri/tauri.prod.conf.json index 7ce4c78420e..9472973ad70 100644 --- a/packages/desktop/src-tauri/tauri.prod.conf.json +++ b/packages/desktop/src-tauri/tauri.prod.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "OpenCode", - "identifier": "ai.opencode.desktop", + "productName": "Shuvcode", + "identifier": "dev.shuvcode.desktop", "bundle": { "createUpdaterArtifacts": true, "icon": [ @@ -27,7 +27,7 @@ "plugins": { "updater": { "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEYwMDM5Nzg5OUMzOUExMDQKUldRRW9UbWNpWmNEOENYT01CV0lhOXR1UFhpaXJsK1Z3aU9lZnNtNzE0TDROWVMwVW9XQnFOelkK", - "endpoints": ["https://github.com/anomalyco/opencode/releases/latest/download/latest.json"] + "endpoints": ["https://github.com/Latitudes-Dev/shuvcode/releases/latest/download/latest.json"] } } } diff --git a/packages/desktop/src/menu.ts b/packages/desktop/src/menu.ts index bf9ca4b8a8b..02f23ec772d 100644 --- a/packages/desktop/src/menu.ts +++ b/packages/desktop/src/menu.ts @@ -10,7 +10,7 @@ export async function createMenu() { const menu = await Menu.new({ items: [ await Submenu.new({ - text: "OpenCode", + text: "Shuvcode", items: [ await PredefinedMenuItem.new({ item: { About: null }, diff --git a/packages/desktop/src/updater.ts b/packages/desktop/src/updater.ts index 4753ee66390..f01014042e0 100644 --- a/packages/desktop/src/updater.ts +++ b/packages/desktop/src/updater.ts @@ -4,7 +4,8 @@ import { ask, message } from "@tauri-apps/plugin-dialog" import { invoke } from "@tauri-apps/api/core" import { type as ostype } from "@tauri-apps/plugin-os" -export const UPDATER_ENABLED = window.__OPENCODE__?.updaterEnabled ?? false +export const UPDATER_ENABLED = + window.__SHUVCODE__?.updaterEnabled ?? window.__OPENCODE__?.updaterEnabled ?? false export async function runUpdater({ alertOnFail }: { alertOnFail: boolean }) { let update @@ -17,7 +18,7 @@ export async function runUpdater({ alertOnFail }: { alertOnFail: boolean }) { if (!update) { if (alertOnFail) - await message("You are already using the latest version of OpenCode", { title: "No Update Available" }) + await message("You are already using the latest version of Shuvcode", { title: "No Update Available" }) return } @@ -29,7 +30,7 @@ export async function runUpdater({ alertOnFail }: { alertOnFail: boolean }) { } const shouldUpdate = await ask( - `Version ${update.version} of OpenCode has been downloaded, would you like to install it and relaunch?`, + `Version ${update.version} of Shuvcode has been downloaded, would you like to install it and relaunch?`, { title: "Update Downloaded" }, ) if (!shouldUpdate) return diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 811e8571787..fd3a4baab6c 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.1.4", + "version": "1.1.4-1", "private": true, "type": "module", "license": "MIT", diff --git a/packages/enterprise/src/entry-server.tsx b/packages/enterprise/src/entry-server.tsx index 989c3c088b1..002518c51aa 100644 --- a/packages/enterprise/src/entry-server.tsx +++ b/packages/enterprise/src/entry-server.tsx @@ -4,13 +4,20 @@ import { createHandler, StartServer } from "@solidjs/start/server" export default createHandler(() => ( ( - + - OpenCode - - + shuvcode + + + + + {assets} diff --git a/packages/enterprise/src/routes/s/[id].ts b/packages/enterprise/src/routes/s/[id].ts new file mode 100644 index 00000000000..9c7861be98d --- /dev/null +++ b/packages/enterprise/src/routes/s/[id].ts @@ -0,0 +1,12 @@ +import type { APIEvent } from "@solidjs/start/server" + +export function GET(event: APIEvent) { + const url = new URL(event.request.url) + const id = url.pathname.split("/").pop() + return new Response(null, { + status: 301, + headers: { + Location: `/share/${id}`, + }, + }) +} diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index 776b4226451..df3ecb9d35c 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -8,7 +8,7 @@ import { WorkerPoolProvider } from "@opencode-ai/ui/context/worker-pool" import { createAsync, query, useParams } from "@solidjs/router" import { createEffect, createMemo, ErrorBoundary, For, Match, Show, Switch } from "solid-js" import { Share } from "~/core/share" -import { Logo, Mark } from "@opencode-ai/ui/logo" +import { AsciiLogo, AsciiMark } from "@opencode-ai/ui/logo" import { IconButton } from "@opencode-ai/ui/icon-button" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { createDefaultOptions } from "@opencode-ai/ui/pierre" @@ -26,7 +26,6 @@ import { Diff as SSRDiff } from "@opencode-ai/ui/diff-ssr" import { clientOnly } from "@solidjs/start" import { type IconName } from "@opencode-ai/ui/icons/provider" import { Meta, Title } from "@solidjs/meta" -import { Base64 } from "js-base64" const ClientOnlyDiff = clientOnly(() => import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff }))) const ClientOnlyCode = clientOnly(() => import("@opencode-ai/ui/code").then((m) => ({ default: m.Code }))) @@ -186,35 +185,16 @@ export default function () { if (!match().found) throw new Error(`Session ${data().sessionID} not found`) const info = createMemo(() => data().session[match().index]) const ogImage = createMemo(() => { - const models = new Set() - const messages = data().message[data().sessionID] ?? [] - for (const msg of messages) { - if (msg.role === "assistant" && msg.modelID) { - models.add(msg.modelID) - } - } - const modelIDs = Array.from(models) - const encodedTitle = encodeURIComponent(Base64.encode(encodeURIComponent(info().title.substring(0, 700)))) - let modelParam: string - if (modelIDs.length === 1) { - modelParam = modelIDs[0] - } else if (modelIDs.length === 2) { - modelParam = encodeURIComponent(`${modelIDs[0]} & ${modelIDs[1]}`) - } else if (modelIDs.length > 2) { - modelParam = encodeURIComponent(`${modelIDs[0]} & ${modelIDs.length - 1} others`) - } else { - modelParam = "unknown" - } - const version = `v${info().version}` - return `https://social-cards.sst.dev/opencode-share/${encodedTitle}.png?model=${modelParam}&version=${version}&id=${data().shareID}` + // Use static fallback image for shuvcode + return `/social-share.png` }) return ( <> - {info().title} | OpenCode + {info().title} | shuvcode - + @@ -224,7 +204,6 @@ export default function () { {iife(() => { const [store, setStore] = createStore({ messageId: undefined as string | undefined, - expandedSteps: {} as Record, }) const messages = createMemo(() => data().sessionID @@ -266,22 +245,20 @@ export default function () { const title = () => (
    -
    -
    - +
    +
    +
    v{info().version}
    -
    -
    - -
    {model()?.name ?? modelID()}
    -
    -
    - {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} -
    +
    + +
    {model()?.name ?? modelID()}
    +
    +
    + {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
    {info().title}
    @@ -289,16 +266,14 @@ export default function () { ) const turns = () => ( -
    -
    {title()}
    +
    +
    {title()}
    {(message) => ( setStore("expandedSteps", message.id, (v) => !v)} classes={{ root: "min-w-0 w-full relative", content: @@ -310,7 +285,7 @@ export default function () {
    - +
    ) @@ -320,15 +295,13 @@ export default function () { return (
    -
    - - - +
    +
    1, "px-6": !wide() && messages().length === 1, }} @@ -376,20 +349,13 @@ export default function () { { - const id = store.messageId ?? firstUserMessage()!.id! - setStore("expandedSteps", id, (v) => !v) - }} classes={{ root: "grow", - content: "flex flex-col justify-between", + content: "flex flex-col justify-between items-start", container: "w-full pb-20 " + (wide() - ? "max-w-200 mx-auto px-6" + ? "max-w-146 mx-auto px-6" : messages().length > 1 ? "pr-6 pl-18" : "px-6"), @@ -398,7 +364,7 @@ export default function () {
    - +
    diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 79c8e2ab51a..c080129c801 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.1.4" +version = "1.1.4-1" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/anomalyco/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4-1/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4-1/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4-1/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4-1/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.4-1/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 4db6d75b8be..0a4ac887fa3 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.1.4", + "version": "1.1.4-1", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/function/src/api.ts b/packages/function/src/api.ts index 6f00dae9a2a..b20fb43789c 100644 --- a/packages/function/src/api.ts +++ b/packages/function/src/api.ts @@ -204,7 +204,7 @@ export default new Hono<{ Bindings: Env }>() * Used by the GitHub action to get GitHub installation access token given the OIDC token */ .post("/exchange_github_app_token", async (c) => { - const EXPECTED_AUDIENCE = "opencode-github-action" + const EXPECTED_AUDIENCE = "shuvcode-github-action" const GITHUB_ISSUER = "https://token.actions.githubusercontent.com" const JWKS_URL = `${GITHUB_ISSUER}/.well-known/jwks` diff --git a/packages/opencode/.gitignore b/packages/opencode/.gitignore index e057ca61f94..4372a33e608 100644 --- a/packages/opencode/.gitignore +++ b/packages/opencode/.gitignore @@ -2,3 +2,4 @@ research dist gen app.log +static diff --git a/packages/opencode/Dockerfile b/packages/opencode/Dockerfile index f92b48a6d1b..875dc44f41f 100644 --- a/packages/opencode/Dockerfile +++ b/packages/opencode/Dockerfile @@ -1,18 +1,59 @@ -FROM alpine AS base +# Multi-stage Dockerfile that builds shuvcode from source +# +# Build: docker build -t shuvcode:local . +# Run: docker run -p 4096:4096 shuvcode:local + +# Stage 1: Build the CLI binary and desktop UI +FROM oven/bun:1 AS builder + +# Install git (needed by build script to detect branch) +RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Copy everything (bun workspaces need the full structure) +COPY . . + +# Install dependencies +RUN bun install + +# Build the desktop UI +RUN cd packages/desktop && bun run build + +# Build the CLI (all platforms - needed because runtime is Alpine/musl) +# Set channel to "docker" since .git is not available in build context +ENV OPENCODE_CHANNEL=docker +RUN cd packages/opencode && bun run build + +# Copy desktop build to static directory +RUN cp -r packages/desktop/dist packages/opencode/static + +# Stage 2: Runtime image +FROM alpine -# Disable the runtime transpiler cache by default inside Docker containers. -# On ephemeral containers, the cache is not useful ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} -RUN apk add libgcc libstdc++ ripgrep -FROM base AS build-amd64 -COPY dist/opencode-linux-x64-baseline-musl/bin/opencode /usr/local/bin/opencode +RUN apk add --no-cache libgcc libstdc++ ripgrep git \ + && git config --global init.defaultBranch main + +# Git user config - override these at runtime via environment variables +ENV GIT_AUTHOR_NAME="shuvcode" \ + GIT_AUTHOR_EMAIL="shuvcode@localhost" \ + GIT_COMMITTER_NAME="shuvcode" \ + GIT_COMMITTER_EMAIL="shuvcode@localhost" + +# Detect architecture and copy appropriate binary +ARG TARGETARCH=amd64 +COPY --from=builder /app/packages/opencode/dist/shuvcode-linux-x64-baseline-musl/bin/shuvcode /tmp/shuvcode-amd64 +COPY --from=builder /app/packages/opencode/dist/shuvcode-linux-arm64-musl/bin/shuvcode /tmp/shuvcode-arm64 +RUN cp /tmp/shuvcode-${TARGETARCH} /usr/local/bin/shuvcode && rm /tmp/shuvcode-* + +COPY --from=builder /app/packages/opencode/static /usr/local/bin/static + +RUN shuvcode --version -FROM base AS build-arm64 -COPY dist/opencode-linux-arm64-musl/bin/opencode /usr/local/bin/opencode +EXPOSE 4096 -ARG TARGETARCH -FROM build-${TARGETARCH} -RUN opencode --version -ENTRYPOINT ["opencode"] +ENTRYPOINT ["shuvcode"] +CMD ["serve", "--port", "4096", "--hostname", "0.0.0.0"] diff --git a/packages/opencode/bin/opencode b/packages/opencode/bin/shuvcode similarity index 89% rename from packages/opencode/bin/opencode rename to packages/opencode/bin/shuvcode index e35cc00944d..5031240c481 100755 --- a/packages/opencode/bin/opencode +++ b/packages/opencode/bin/shuvcode @@ -44,8 +44,8 @@ let arch = archMap[os.arch()] if (!arch) { arch = os.arch() } -const base = "opencode-" + platform + "-" + arch -const binary = platform === "windows" ? "opencode.exe" : "opencode" +const base = "shuvcode-" + platform + "-" + arch +const binary = platform === "windows" ? "shuvcode.exe" : "shuvcode" function findBinary(startDir) { let current = startDir @@ -74,7 +74,7 @@ function findBinary(startDir) { const resolved = findBinary(scriptDir) if (!resolved) { console.error( - 'It seems that your package manager failed to install the right version of the opencode CLI for your platform. You can try manually installing the "' + + 'It seems that your package manager failed to install the right version of shuvcode for your platform. You can try manually installing the "' + base + '" package', ) diff --git a/packages/opencode/package.json b/packages/opencode/package.json index f9ee3a3e5de..c4edd670f1a 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.1.4", + "version": "1.1.4-1", "name": "opencode", "type": "module", "license": "MIT", @@ -97,6 +97,7 @@ "decimal.js": "10.5.0", "diff": "catalog:", "fuzzysort": "3.1.0", + "ghostty-opentui": "1.3.7", "gray-matter": "4.0.3", "hono": "catalog:", "hono-openapi": "catalog:", diff --git a/packages/opencode/postinstall.mjs b/packages/opencode/postinstall.mjs new file mode 100644 index 00000000000..31d3b9dad49 --- /dev/null +++ b/packages/opencode/postinstall.mjs @@ -0,0 +1,140 @@ +#!/usr/bin/env node + +import fs from "fs" +import path from "path" +import os from "os" +import { fileURLToPath } from "url" +import { createRequire } from "module" + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const require = createRequire(import.meta.url) + +function detectPlatformAndArch() { + // Map platform names + let platform + switch (os.platform()) { + case "darwin": + platform = "darwin" + break + case "linux": + platform = "linux" + break + case "win32": + platform = "windows" + break + default: + platform = os.platform() + break + } + + // Map architecture names + let arch + switch (os.arch()) { + case "x64": + arch = "x64" + break + case "arm64": + arch = "arm64" + break + case "arm": + arch = "arm" + break + default: + arch = os.arch() + break + } + + return { platform, arch } +} + +function findBinary() { + const { platform, arch } = detectPlatformAndArch() + const basePackageName = `shuvcode-${platform}-${arch}` + const binaryName = platform === "windows" ? "shuvcode.exe" : "shuvcode" + + try { + // Try exact package name first + try { + const packageJsonPath = require.resolve(`${basePackageName}/package.json`) + const packageDir = path.dirname(packageJsonPath) + const binaryPath = path.join(packageDir, "bin", binaryName) + + if (fs.existsSync(binaryPath)) { + return { binaryPath, binaryName } + } + } catch (error) { + // Exact match failed, try baseline variant + } + + // Fallback: search for baseline variants (e.g., shuvcode-linux-x64-baseline) + const nodeModulesPath = path.join(__dirname, "..") + if (fs.existsSync(nodeModulesPath)) { + const entries = fs.readdirSync(nodeModulesPath) + for (const entry of entries) { + if (entry.startsWith(basePackageName)) { + const binaryPath = path.join(nodeModulesPath, entry, "bin", binaryName) + if (fs.existsSync(binaryPath)) { + return { binaryPath, binaryName } + } + } + } + } + + throw new Error(`No binary package found for ${basePackageName}`) + } catch (error) { + throw new Error(`Could not find package ${basePackageName}: ${error.message}`) + } +} + +function prepareBinDirectory(binaryName) { + const binDir = path.join(__dirname, "bin") + const targetPath = path.join(binDir, binaryName) + + // Ensure bin directory exists + if (!fs.existsSync(binDir)) { + fs.mkdirSync(binDir, { recursive: true }) + } + + // Remove existing binary/symlink if it exists + if (fs.existsSync(targetPath)) { + fs.unlinkSync(targetPath) + } + + return { binDir, targetPath } +} + +function symlinkBinary(sourcePath, binaryName) { + const { targetPath } = prepareBinDirectory(binaryName) + + fs.symlinkSync(sourcePath, targetPath) + console.log(`shuvcode binary symlinked: ${targetPath} -> ${sourcePath}`) + + // Verify the file exists after operation + if (!fs.existsSync(targetPath)) { + throw new Error(`Failed to symlink binary to ${targetPath}`) + } +} + +async function main() { + try { + if (os.platform() === "win32") { + // On Windows, the .exe is already included in the package and bin field points to it + // No postinstall setup needed + console.log("Windows detected: binary setup not needed (using packaged .exe)") + return + } + + const { binaryPath, binaryName } = findBinary() + symlinkBinary(binaryPath, binaryName) + } catch (error) { + console.error("Failed to setup shuvcode binary:", error.message) + process.exit(1) + } +} + +try { + main() +} catch (error) { + console.error("Postinstall script error:", error.message) + process.exit(0) +} diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index f51cb292411..de494ed1edb 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import solidPlugin from "../node_modules/@opentui/solid/scripts/solid-plugin" +import solidPlugin from "@opentui/solid/bun-plugin" import path from "path" import fs from "fs" import { $ } from "bun" @@ -97,13 +97,15 @@ const targets = singleFlag await $`rm -rf dist` const binaries: Record = {} +const deps = pkg.dependencies as Record if (!skipInstall) { - await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}` - await $`bun install --os="*" --cpu="*" @parcel/watcher@${pkg.dependencies["@parcel/watcher"]}` + await $`bun install --os="*" --cpu="*" @opentui/core@${deps["@opentui/core"]}` + await $`bun install --os="*" --cpu="*" @parcel/watcher@${deps["@parcel/watcher"]}` + await $`bun install --os="*" --cpu="*" ghostty-opentui@${deps["ghostty-opentui"]}` } for (const item of targets) { const name = [ - pkg.name, + "shuvcode", // Use shuvcode prefix for binary packages // changing to win32 flags npm for some reason item.os === "win32" ? "windows" : item.os, item.arch, @@ -112,7 +114,9 @@ for (const item of targets) { ] .filter(Boolean) .join("-") - console.log(`building ${name}`) + // Bun compile target (e.g., bun-linux-x64) + const bunTarget = name.replace("shuvcode", "bun") + console.log(`building ${name} (target: ${bunTarget})`) await $`mkdir -p dist/${name}/bin` const parserWorker = fs.realpathSync(path.resolve(dir, "./node_modules/@opentui/core/parser.worker.js")) @@ -133,14 +137,16 @@ for (const item of targets) { //@ts-ignore (bun types aren't up to date) autoloadTsconfig: true, autoloadPackageJson: true, - target: name.replace(pkg.name, "bun") as any, - outfile: `dist/${name}/bin/opencode`, - execArgv: [`--user-agent=opencode/${Script.version}`, "--"], + target: bunTarget as any, + outfile: `dist/${name}/bin/shuvcode`, + execArgv: [`--user-agent=shuvcode/${Script.version}`, "--"], windows: {}, }, entrypoints: ["./src/index.ts", parserWorker, workerPath], define: { OPENCODE_VERSION: `'${Script.version}'`, + OPENCODE_BASE_VERSION: `'${Script.baseVersion}'`, + OPENCODE_COMMIT_HASH: `'${Script.commitHash}'`, OTUI_TREE_SITTER_WORKER_PATH: bunfsRoot + workerRelativePath, OPENCODE_WORKER_PATH: workerPath, OPENCODE_CHANNEL: `'${Script.channel}'`, @@ -156,6 +162,10 @@ for (const item of targets) { version: Script.version, os: [item.os], cpu: [item.arch], + repository: { + type: "git", + url: "https://github.com/Latitudes-Dev/shuvcode", + }, }, null, 2, diff --git a/packages/opencode/script/postinstall.mjs b/packages/opencode/script/postinstall.mjs index 78f022c9f85..b2378f55235 100644 --- a/packages/opencode/script/postinstall.mjs +++ b/packages/opencode/script/postinstall.mjs @@ -49,7 +49,7 @@ function detectPlatformAndArch() { function findBinary() { const { platform, arch } = detectPlatformAndArch() - const packageName = `opencode-${platform}-${arch}` + const packageName = `shuvcode-${platform}-${arch}` const binaryName = platform === "windows" ? "opencode.exe" : "opencode" try { diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index 4e5846d27ed..0f3f31070b4 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -9,62 +9,56 @@ process.chdir(dir) const { binaries } = await import("./build.ts") { - const name = `${pkg.name}-${process.platform}-${process.arch}` - console.log(`smoke test: running dist/${name}/bin/opencode --version`) - await $`./dist/${name}/bin/opencode --version` + const name = `shuvcode-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}` + console.log(`smoke test: running dist/${name}/bin/shuvcode --version`) + await $`./dist/${name}/bin/shuvcode --version` +} + +// Publish binary packages first using npm with OIDC trusted publishing +// For integration channel, tag as "latest" so users get updates by default +const publishTag = Script.channel === "integration" ? "latest" : Script.channel +for (const name of Object.keys(binaries)) { + console.log(`publishing binary package: ${name}`) + await $`cd ./dist/${name} && npm publish --access public --tag ${publishTag}`.nothrow() } await $`mkdir -p ./dist/${pkg.name}` await $`cp -r ./bin ./dist/${pkg.name}/bin` -await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs` await Bun.file(`./dist/${pkg.name}/package.json`).write( JSON.stringify( { - name: pkg.name + "-ai", + name: "shuvcode", bin: { - [pkg.name]: `./bin/${pkg.name}`, - }, - scripts: { - postinstall: "bun ./postinstall.mjs || node ./postinstall.mjs", + shuvcode: "./bin/shuvcode", }, version: Script.version, + // Reference our own binary packages (shuvcode-linux-x64, etc.) optionalDependencies: binaries, + repository: { + type: "git", + url: "https://github.com/Latitudes-Dev/shuvcode", + }, }, null, 2, ), ) - -const tags = [Script.channel] - -const tasks = Object.entries(binaries).map(async ([name]) => { - if (process.platform !== "win32") { - await $`chmod -R 755 .`.cwd(`./dist/${name}`) - } - await $`bun pm pack`.cwd(`./dist/${name}`) - for (const tag of tags) { - await $`npm publish *.tgz --access public --tag ${tag}`.cwd(`./dist/${name}`) - } -}) -await Promise.all(tasks) -for (const tag of tags) { - await $`cd ./dist/${pkg.name} && bun pm pack && npm publish *.tgz --access public --tag ${tag}` -} +// Use npm publish with OIDC trusted publishing +// For integration channel, tag as "latest" so users get updates by default +await $`cd ./dist/${pkg.name} && npm publish --access public --tag ${publishTag}` if (!Script.preview) { - // Create archives for GitHub release for (const key of Object.keys(binaries)) { if (key.includes("linux")) { - await $`tar -czf ../../${key}.tar.gz *`.cwd(`dist/${key}/bin`) + await $`cd dist/${key}/bin && tar -czf ../../${key}.tar.gz *` } else { - await $`zip -r ../../${key}.zip *`.cwd(`dist/${key}/bin`) + await $`cd dist/${key}/bin && zip -r ../../${key}.zip *` } } - const image = "ghcr.io/anomalyco/opencode" - const platforms = "linux/amd64,linux/arm64" - const tags = [`${image}:${Script.version}`, `${image}:latest`] - const tagFlags = tags.flatMap((t) => ["-t", t]) - await $`docker buildx build --platform ${platforms} ${tagFlags} --push .` + // Skip upstream-specific publishing (AUR, Homebrew, Docker) for fork + // These distribution channels are managed by the upstream sst/opencode project + // Our fork publishes to npm as "shuvcode" and creates GitHub releases on Latitudes-Dev/shuvcode + console.log("Skipping AUR, Homebrew, and Docker publishing (upstream-only)") } diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 21859186659..b157a423930 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -21,6 +21,7 @@ export namespace Agent { mode: z.enum(["subagent", "primary", "all"]), native: z.boolean().optional(), hidden: z.boolean().optional(), + default: z.boolean().optional(), topP: z.number().optional(), temperature: z.number().optional(), color: z.string().optional(), @@ -193,6 +194,17 @@ export namespace Agent { item.options = mergeDeep(item.options, value.options ?? {}) item.permission = PermissionNext.merge(item.permission, PermissionNext.fromConfig(value.permission ?? {})) } + + // Mark the default agent + const defaultName = cfg.default_agent ?? "build" + const defaultCandidate = result[defaultName] + if (defaultCandidate && defaultCandidate.mode !== "subagent") { + defaultCandidate.default = true + } else if (result["build"]) { + // Fall back to "build" if configured default is invalid + result["build"].default = true + } + return result }) @@ -209,8 +221,10 @@ export namespace Agent { ) } - export async function defaultAgent() { - return state().then((x) => Object.keys(x)[0]) + export async function defaultAgent(): Promise { + const agents = await state() + const defaultCandidate = Object.values(agents).find((a) => a.default) + return defaultCandidate?.name ?? "build" } export async function generate(input: { description: string; model?: { providerID: string; modelID: string } }) { diff --git a/packages/opencode/src/askquestion/index.ts b/packages/opencode/src/askquestion/index.ts new file mode 100644 index 00000000000..4ec61d6ecb9 --- /dev/null +++ b/packages/opencode/src/askquestion/index.ts @@ -0,0 +1,161 @@ +import { BusEvent } from "@/bus/bus-event" +import z from "zod" + +export namespace AskQuestion { + /** + * Schema for a single question option + */ + export const OptionSchema = z.object({ + value: z.string().describe("Short identifier for the option"), + label: z.string().describe("Display label for the option"), + description: z.string().optional().describe("Additional context for the option"), + }) + export type Option = z.infer + + /** + * Schema for a single question in the wizard + */ + export const QuestionSchema = z.object({ + id: z.string().describe("Unique identifier for the question"), + label: z.string().describe("Short tab label, e.g. 'UI Framework'"), + question: z.string().describe("The full question to ask the user"), + options: z.array(OptionSchema).min(2).max(8).describe("2-8 suggested answer options"), + multiSelect: z.boolean().optional().describe("Allow selecting multiple options"), + }) + export type Question = z.infer + + /** + * Schema for a single answer from the user + */ + export const AnswerSchema = z.object({ + questionId: z.string().describe("ID of the question being answered"), + values: z.array(z.string()).describe("Selected option value(s)"), + customText: z.string().optional().describe("Custom text if user typed their own response"), + }) + export type Answer = z.infer + + /** + * Bus events for askquestion flow + */ + export const Event = { + /** + * Published by the askquestion tool when it needs user input + */ + Requested: BusEvent.define( + "askquestion.requested", + z.object({ + sessionID: z.string(), + messageID: z.string(), + callID: z.string(), + questions: z.array(QuestionSchema), + }), + ), + + /** + * Published by the TUI when user submits answers + */ + Answered: BusEvent.define( + "askquestion.answered", + z.object({ + sessionID: z.string(), + callID: z.string(), + answers: z.array(AnswerSchema), + }), + ), + + /** + * Published when user cancels the question wizard + */ + Cancelled: BusEvent.define( + "askquestion.cancelled", + z.object({ + sessionID: z.string(), + callID: z.string(), + }), + ), + } + + /** + * Pending askquestion requests waiting for user response + */ + interface PendingRequest { + sessionID: string + messageID: string + callID: string + questions: Question[] + resolve: (answers: Answer[]) => void + reject: (error: Error) => void + } + + // Global map of pending requests by callID + const pendingRequests = new Map() + + /** + * Register a pending askquestion request + */ + export function register( + callID: string, + sessionID: string, + messageID: string, + questions: Question[], + ): Promise { + return new Promise((resolve, reject) => { + pendingRequests.set(callID, { + sessionID, + messageID, + callID, + questions, + resolve, + reject, + }) + }) + } + + /** + * Get a pending request + */ + export function get(callID: string): PendingRequest | undefined { + return pendingRequests.get(callID) + } + + /** + * Get all pending requests for a session + */ + export function getForSession(sessionID: string): PendingRequest[] { + return Array.from(pendingRequests.values()).filter((r) => r.sessionID === sessionID) + } + + /** + * Respond to a pending askquestion request + */ + export function respond(callID: string, answers: Answer[]): boolean { + const pending = pendingRequests.get(callID) + if (!pending) return false + pending.resolve(answers) + pendingRequests.delete(callID) + return true + } + + /** + * Cancel a pending askquestion request + */ + export function cancel(callID: string): boolean { + const pending = pendingRequests.get(callID) + if (!pending) return false + pending.reject(new Error("User cancelled the question wizard")) + pendingRequests.delete(callID) + return true + } + + /** + * Clean up pending requests for a session (e.g., on abort) + */ + export function cleanup(sessionID: string): void { + for (const [callID, request] of pendingRequests) { + if (request.sessionID === sessionID) { + request.reject(new Error("Session aborted")) + pendingRequests.delete(callID) + } + } + } +} diff --git a/packages/opencode/src/bun/index.ts b/packages/opencode/src/bun/index.ts index fe2f0dec371..1e093469fe5 100644 --- a/packages/opencode/src/bun/index.ts +++ b/packages/opencode/src/bun/index.ts @@ -6,6 +6,7 @@ import { NamedError } from "@opencode-ai/util/error" import { readableStreamToText } from "bun" import { createRequire } from "module" import { Lock } from "../util/lock" +import { copyPluginAssets } from "../util/asset-copy" export namespace BunProc { const log = Log.create({ service: "bun" }) @@ -65,13 +66,20 @@ export namespace BunProc { using _ = await Lock.write("bun-install") const mod = path.join(Global.Path.cache, "node_modules", pkg) + const bundledDir = path.join(Global.Path.cache, "bundled") + const bundledFile = path.join(bundledDir, `${pkg.replace(/\//g, "-")}.js`) const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json")) const parsed = await pkgjson.json().catch(async () => { - const result = { dependencies: {} } + const result = { dependencies: {}, bundled: {} } await Bun.write(pkgjson.name!, JSON.stringify(result, null, 2)) return result }) - if (parsed.dependencies[pkg] === version) return mod + + // Check if already installed and bundled + const bundledExists = await Bun.file(bundledFile).exists() + if (parsed.dependencies[pkg] === version && bundledExists) { + return bundledFile + } const proxied = !!( process.env.HTTP_PROXY || @@ -114,17 +122,104 @@ export namespace BunProc { // Resolve actual version from installed package when using "latest" // This ensures subsequent starts use the cached version until explicitly updated + const installedPkgJson = Bun.file(path.join(mod, "package.json")) + const installedPkg = await installedPkgJson.json().catch(() => null) let resolvedVersion = version - if (version === "latest") { - const installedPkgJson = Bun.file(path.join(mod, "package.json")) - const installedPkg = await installedPkgJson.json().catch(() => null) - if (installedPkg?.version) { - resolvedVersion = installedPkg.version + if (version === "latest" && installedPkg?.version) { + resolvedVersion = installedPkg.version + } + + const tslibPath = path.join(Global.Path.cache, "node_modules", "tslib", "package.json") + const tslibExists = await Bun.file(tslibPath).exists() + if (!tslibExists) { + const resolvedTslibVersion = "latest" + log.info("installing tslib dependency for runtime compatibility", { + pkg, + tslib: resolvedTslibVersion, + }) + await BunProc.run([ + "add", + "--force", + "--exact", + "--cwd", + Global.Path.cache, + `tslib@${resolvedTslibVersion}`, + ], { + cwd: Global.Path.cache, + }).catch((e) => { + throw new InstallFailedError( + { pkg: "tslib", version: resolvedTslibVersion }, + { + cause: e, + }, + ) + }) + } + + // Bundle the plugin with all dependencies for compiled binary compatibility + // This creates a single file that doesn't require subpath export resolution + await Bun.file(bundledDir) + .exists() + .then(async (exists) => { + if (!exists) await Bun.$`mkdir -p ${bundledDir}` + }) + + // Find the entry point from package.json + const entryPoint = (installedPkg ?? {}).main || "index.js" + const entryPath = path.join(mod, entryPoint) + + log.info("bundling plugin for compiled binary compatibility", { + pkg, + entryPath, + bundledFile, + }) + + try { + const result = await Bun.build({ + entrypoints: [entryPath], + outdir: bundledDir, + naming: `${pkg.replace(/\//g, "-")}.js`, + target: "bun", + format: "esm", + // Bundle all dependencies to avoid subpath export resolution issues + packages: "bundle", + }) + + if (!result.success) { + log.error("failed to bundle plugin - falling back to unbundled module", { + pkg, + logs: result.logs, + unbundledPath: mod, + }) + // Fall back to unbundled module + return mod } + + log.info("successfully bundled plugin", { + pkg, + bundledFile, + }) + + // Copy non-JS assets (HTML, CSS, etc.) that plugins may need at runtime + // Some bundled code uses __dirname + ".." to find assets, so copy to both + // the bundled dir and the parent cache dir for compatibility + await copyPluginAssets(mod, bundledDir) + await copyPluginAssets(mod, Global.Path.cache) + } catch (e) { + log.error("failed to bundle plugin - falling back to unbundled module", { + pkg, + error: (e as Error).message, + unbundledPath: mod, + }) + // Fall back to unbundled module + return mod } parsed.dependencies[pkg] = resolvedVersion + if (!parsed.bundled) parsed.bundled = {} + parsed.bundled[pkg] = bundledFile await Bun.write(pkgjson.name!, JSON.stringify(parsed, null, 2)) - return mod + return bundledFile } + } diff --git a/packages/opencode/src/cli/cmd/cache.ts b/packages/opencode/src/cli/cmd/cache.ts new file mode 100644 index 00000000000..7985353efe5 --- /dev/null +++ b/packages/opencode/src/cli/cmd/cache.ts @@ -0,0 +1,119 @@ +import type { Argv } from "yargs" +import { cmd } from "./cmd" +import * as prompts from "@clack/prompts" +import { Global } from "../../global" +import { getDirectorySize, formatSize, shortenPath } from "../util" +import fs from "fs/promises" +import path from "path" + +const CacheCleanCommand = cmd({ + command: "clean", + describe: "remove cached plugins and packages", + builder: (yargs: Argv) => + yargs + .option("force", { + alias: "f", + type: "boolean", + describe: "skip confirmation prompt", + default: false, + }) + .option("dry-run", { + type: "boolean", + describe: "show what would be removed without removing", + default: false, + }), + async handler(args) { + const exists = await fs + .access(Global.Path.cache) + .then(() => true) + .catch(() => false) + + if (!exists) { + prompts.log.info("Cache directory does not exist") + return + } + + const size = await getDirectorySize(Global.Path.cache) + + prompts.log.info(`Cache: ${shortenPath(Global.Path.cache)} (${formatSize(size)})`) + + if (args.dryRun) { + prompts.log.warn("Dry run - no changes made") + return + } + + if (!args.force) { + const confirm = await prompts.confirm({ + message: "Remove cache directory?", + initialValue: true, + }) + if (!confirm || prompts.isCancel(confirm)) { + prompts.log.warn("Cancelled") + return + } + } + + const spinner = prompts.spinner() + spinner.start("Removing cache...") + + const err = await fs.rm(Global.Path.cache, { recursive: true, force: true }).catch((e) => e) + if (err) { + spinner.stop("Failed to remove cache", 1) + prompts.log.error(err.message) + return + } + + spinner.stop("Cache removed") + }, +}) + +const CacheInfoCommand = cmd({ + command: "info", + describe: "show cache directory information", + async handler() { + const exists = await fs + .access(Global.Path.cache) + .then(() => true) + .catch(() => false) + + prompts.log.info(`Path: ${shortenPath(Global.Path.cache)}`) + + if (!exists) { + prompts.log.info("Status: not created") + return + } + + const size = await getDirectorySize(Global.Path.cache) + prompts.log.info(`Size: ${formatSize(size)}`) + + const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json")) + const parsed = await pkgjson.json().catch(() => null) + + if (parsed?.dependencies) { + const deps = Object.entries(parsed.dependencies) + if (deps.length > 0) { + prompts.log.info(`Packages:`) + for (const [pkg, version] of deps) { + prompts.log.info(` ${pkg}@${version}`) + } + } + } + + const versionFile = Bun.file(path.join(Global.Path.cache, "version")) + const version = await versionFile.text().catch(() => null) + if (version) { + prompts.log.info(`Cache version: ${version.trim()}`) + } + }, +}) + +export const CacheCommand = cmd({ + command: "cache", + describe: "manage plugin and package cache", + builder: (yargs) => + yargs + .command(CacheCleanCommand) + .command(CacheInfoCommand) + .demandCommand(1, "Please specify a subcommand: clean or info"), + async handler() {}, +}) diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index f6c6b688a35..2890d14a531 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -131,9 +131,9 @@ type IssueQueryResponse = { } } -const AGENT_USERNAME = "opencode-agent[bot]" +const AGENT_USERNAME = "shuvcode-agent[bot]" const AGENT_REACTION = "eyes" -const WORKFLOW_FILE = ".github/workflows/opencode.yml" +const WORKFLOW_FILE = ".github/workflows/shuvcode.yml" // Event categories for routing // USER_EVENTS: triggered by user actions, have actor/issueId, support reactions/comments @@ -234,9 +234,9 @@ export const GithubInstallCommand = cmd({ ` 1. Commit the \`${WORKFLOW_FILE}\` file and push`, step2, "", - " 3. Go to a GitHub issue and comment `/oc summarize` to see the agent in action", + " 3. Go to a GitHub issue and comment `/shuv summarize` to see the agent in action", "", - " Learn more about the GitHub agent - https://opencode.ai/docs/github/#usage-examples", + " Learn more about the GitHub agent - https://github.com/Latitudes-Dev/shuvcode", ].join("\n"), ) } @@ -318,7 +318,7 @@ export const GithubInstallCommand = cmd({ if (installation) return s.stop("GitHub app already installed") // Open browser - const url = "https://github.com/apps/opencode-agent" + const url = "https://github.com/apps/shuvcode-agent" const command = process.platform === "darwin" ? `open "${url}"` @@ -355,7 +355,7 @@ export const GithubInstallCommand = cmd({ async function getInstallation() { return await fetch( - `https://api.opencode.ai/get_github_app_installation?owner=${app.owner}&repo=${app.repo}`, + `https://api.shuv.ai/get_github_app_installation?owner=${app.owner}&repo=${app.repo}`, ) .then((res) => res.json()) .then((data) => data.installation) @@ -370,7 +370,7 @@ export const GithubInstallCommand = cmd({ await Bun.write( path.join(app.root, WORKFLOW_FILE), - `name: opencode + `name: shuvcode on: issue_comment: @@ -379,12 +379,12 @@ on: types: [created] jobs: - opencode: + shuvcode: if: | - contains(github.event.comment.body, ' /oc') || - startsWith(github.event.comment.body, '/oc') || - contains(github.event.comment.body, ' /opencode') || - startsWith(github.event.comment.body, '/opencode') + contains(github.event.comment.body, ' /shuv') || + startsWith(github.event.comment.body, '/shuv') || + contains(github.event.comment.body, ' /shuvcode') || + startsWith(github.event.comment.body, '/shuvcode') runs-on: ubuntu-latest permissions: id-token: write @@ -395,8 +395,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - name: Run opencode - uses: anomalyco/opencode/github@latest${envStr} + - name: Run shuvcode + uses: Latitudes-Dev/shuvcode/github@integration${envStr} with: model: ${provider}/${model}`, ) @@ -465,7 +465,7 @@ export const GithubRunCommand = cmd({ ? (payload as IssueCommentEvent | IssuesEvent).issue.number : (payload as PullRequestEvent | PullRequestReviewCommentEvent).pull_request.number const runUrl = `/${owner}/${repo}/actions/runs/${runId}` - const shareBaseUrl = isMock ? "https://dev.opencode.ai" : "https://opencode.ai" + const shareBaseUrl = isMock ? "https://share.dev.shuv.ai" : "https://share.shuv.ai" let appToken: string let octoRest: Octokit @@ -673,7 +673,7 @@ export const GithubRunCommand = cmd({ function normalizeOidcBaseUrl(): string { const value = process.env["OIDC_BASE_URL"] - if (!value) return "https://api.opencode.ai" + if (!value) return "https://api.shuv.ai" return value.replace(/\/+$/, "") } @@ -722,7 +722,7 @@ export const GithubRunCommand = cmd({ } const reviewContext = getReviewCommentContext() - const mentions = (process.env["MENTIONS"] || "/opencode,/oc") + const mentions = (process.env["MENTIONS"] || "/shuvcode,/shuv,/opencode,/oc") .split(",") .map((m) => m.trim().toLowerCase()) .filter(Boolean) @@ -977,15 +977,34 @@ export const GithubRunCommand = cmd({ }, }) + const safeParseJson = (input: string) => { + try { + return JSON.parse(input) + } catch { + return undefined + } + } + + const type = response.headers.get("content-type") || "" + const body = await response.text() + const json = type.includes("json") || body.trim().startsWith("{") ? safeParseJson(body) : undefined + if (!response.ok) { - const responseJson = (await response.json()) as { error?: string } - throw new Error( - `App token exchange failed: ${response.status} ${response.statusText} - ${responseJson.error}`, - ) + const message = + json && typeof json === "object" && "error" in json + ? (json as { error?: string }).error + : body.slice(0, 500) || "unknown error" + + throw new Error(`App token exchange failed: ${response.status} ${response.statusText} - ${message}`) + } + + if (json && typeof json === "object" && "token" in json) { + return (json as { token: string }).token } - const responseJson = (await response.json()) as { token: string } - return responseJson.token + throw new Error( + `App token exchange failed: missing token in response (${response.status} ${response.statusText}) - ${body.slice(0, 500)}`, + ) } async function configureGit(appToken: string) { @@ -1120,6 +1139,14 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` // Only called for non-schedule events, so actor is defined console.log(`Asserting permissions for user ${actor}...`) + // GitHub App bots don't return proper permissions via the collaborator API + // even when they have write access. Allow trusted bots that are installed on the repo. + const trustedBots = ["shuvcode-agent[bot]", "opencode-agent[bot]", "coderabbitai[bot]"] + if (trustedBots.includes(actor!)) { + console.log(` ${actor} is a trusted bot, skipping permission check`) + return + } + let permission try { const response = await octoRest.repos.getCollaboratorPermissionLevel({ diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index 9d7e8c56171..c0b5cb2d936 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -31,39 +31,90 @@ export const ImportCommand = cmd({ const isUrl = args.file.startsWith("http://") || args.file.startsWith("https://") if (isUrl) { - const urlMatch = args.file.match(/https?:\/\/opncd\.ai\/share\/([a-zA-Z0-9_-]+)/) - if (!urlMatch) { - process.stdout.write(`Invalid URL format. Expected: https://opncd.ai/share/`) - process.stdout.write(EOL) - return - } + // Match upstream (opncd.ai) and enterprise (shuv.ai) URLs + const upstreamMatch = args.file.match(/https?:\/\/opncd\.ai\/share\/([a-zA-Z0-9_-]+)/) + const enterpriseMatch = args.file.match(/https?:\/\/(?:share\.)?shuv\.ai\/(?:share|s)\/([a-zA-Z0-9_-]+)/) - const slug = urlMatch[1] - const response = await fetch(`https://opncd.ai/api/share/${slug}`) + const isUpstream = !!upstreamMatch + const isShuv = !!enterpriseMatch + const slug = upstreamMatch?.[1] ?? enterpriseMatch?.[1] - if (!response.ok) { - process.stdout.write(`Failed to fetch share data: ${response.statusText}`) + if (!slug) { + process.stdout.write(`Invalid URL format. Expected:`) + process.stdout.write(EOL) + process.stdout.write(` - https://opncd.ai/share/`) + process.stdout.write(EOL) + process.stdout.write(` - https://share.shuv.ai/share/`) process.stdout.write(EOL) return } - const data = await response.json() + if (isShuv) { + // Enterprise API format + const response = await fetch(`https://share.shuv.ai/api/share/${slug}/data`) + if (!response.ok) { + process.stdout.write(`Failed to fetch share data: ${response.statusText}`) + process.stdout.write(EOL) + return + } - if (!data.info || !data.messages || Object.keys(data.messages).length === 0) { - process.stdout.write(`Share not found: ${slug}`) - process.stdout.write(EOL) - return - } + const data = (await response.json()) as Array<{ + type: "session" | "message" | "part" | "session_diff" | "model" + data: any + }> - exportData = { - info: data.info, - messages: Object.values(data.messages).map((msg: any) => { - const { parts, ...info } = msg - return { - info, - parts, + // Transform enterprise format to standard format + let info: Session.Info | undefined + const messagesMap: Record = {} + + for (const item of data) { + if (item.type === "session") { + info = item.data + } else if (item.type === "message") { + const msgId = item.data.id + messagesMap[msgId] = messagesMap[msgId] ?? { info: item.data, parts: [] } + messagesMap[msgId].info = item.data + } else if (item.type === "part") { + const msgId = item.data.messageID + messagesMap[msgId] = messagesMap[msgId] ?? { info: {}, parts: [] } + messagesMap[msgId].parts.push(item.data) } - }), + } + + if (!info) { + process.stdout.write(`Share not found: ${slug}`) + process.stdout.write(EOL) + return + } + + exportData = { + info, + messages: Object.values(messagesMap), + } + } else { + // Upstream API format (opncd.ai) + const response = await fetch(`https://opncd.ai/api/share/${slug}`) + if (!response.ok) { + process.stdout.write(`Failed to fetch share data: ${response.statusText}`) + process.stdout.write(EOL) + return + } + + const data = await response.json() + + if (!data.info || !data.messages || Object.keys(data.messages).length === 0) { + process.stdout.write(`Share not found: ${slug}`) + process.stdout.write(EOL) + return + } + + exportData = { + info: data.info, + messages: Object.values(data.messages).map((msg: any) => { + const { parts, ...info } = msg + return { info, parts } + }), + } } } else { const file = Bun.file(args.file) diff --git a/packages/opencode/src/cli/cmd/serve.ts b/packages/opencode/src/cli/cmd/serve.ts index 657f9196c96..aa738962df6 100644 --- a/packages/opencode/src/cli/cmd/serve.ts +++ b/packages/opencode/src/cli/cmd/serve.ts @@ -10,7 +10,16 @@ export const ServeCommand = cmd({ const opts = await resolveNetworkOptions(args) const server = Server.listen(opts) console.log(`opencode server listening on http://${server.hostname}:${server.port}`) + + const stop = async () => { + console.log("stopping server...") + await server.stop() + process.exit(0) + } + + process.on("SIGTERM", stop) + process.on("SIGINT", stop) + await new Promise(() => {}) - await server.stop() }, }) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 2af5b21152c..6dcd10766de 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -2,7 +2,7 @@ import { render, useKeyboard, useRenderer, useTerminalDimensions } from "@opentu import { Clipboard } from "@tui/util/clipboard" import { TextAttributes } from "@opentui/core" import { RouteProvider, useRoute } from "@tui/context/route" -import { Switch, Match, createEffect, untrack, ErrorBoundary, createSignal, onMount, batch, Show, on } from "solid-js" +import { Switch, Match, createEffect, untrack, ErrorBoundary, createSignal, onMount, batch, on } from "solid-js" import { Installation } from "@/installation" import { Flag } from "@/flag/flag" import { DialogProvider, useDialog } from "@tui/ui/dialog" @@ -12,8 +12,11 @@ import { SyncProvider, useSync } from "@tui/context/sync" import { LocalProvider, useLocal } from "@tui/context/local" import { DialogModel, useConnected } from "@tui/component/dialog-model" import { DialogMcp } from "@tui/component/dialog-mcp" +import { DialogTools } from "@tui/component/dialog-tools" +import { DialogIde } from "@tui/component/dialog-ide" import { DialogStatus } from "@tui/component/dialog-status" import { DialogThemeList } from "@tui/component/dialog-theme-list" +import { DialogSpinnerList, DialogSpinnerInterval } from "@tui/component/dialog-spinner" import { DialogHelp } from "./ui/dialog-help" import { CommandProvider, useCommandDialog } from "@tui/component/dialog-command" import { DialogAgent } from "@tui/component/dialog-agent" @@ -22,6 +25,7 @@ import { KeybindProvider } from "@tui/context/keybind" import { ThemeProvider, useTheme } from "@tui/context/theme" import { Home } from "@tui/routes/home" import { Session } from "@tui/routes/session" + import { PromptHistoryProvider } from "./component/prompt/history" import { FrecencyProvider } from "./component/prompt/frecency" import { PromptStashProvider } from "./component/prompt/stash" @@ -97,7 +101,7 @@ async function getTerminalBackgroundColor(): Promise<"dark" | "light"> { }) } -export function tui(input: { url: string; args: Args; directory?: string; onExit?: () => Promise }) { +export function tui(input: { url: string; directory?: string; args: Args; onExit?: () => Promise }) { // promise to prevent immediate exit return new Promise(async (resolve) => { const mode = await getTerminalBackgroundColor() @@ -177,7 +181,7 @@ function App() { const command = useCommandDialog() const sdk = useSDK() const toast = useToast() - const { theme, mode, setMode } = useTheme() + const { theme, mode, setMode, transparent, setTransparent } = useTheme() const sync = useSync() const exit = useExit() const promptRef = usePromptRef() @@ -207,20 +211,20 @@ function App() { if (!terminalTitleEnabled() || Flag.OPENCODE_DISABLE_TERMINAL_TITLE) return if (route.data.type === "home") { - renderer.setTerminalTitle("OpenCode") + renderer.setTerminalTitle("shuvcode") return } if (route.data.type === "session") { const session = sync.session.get(route.data.sessionID) if (!session || SessionApi.isDefaultTitle(session.title)) { - renderer.setTerminalTitle("OpenCode") + renderer.setTerminalTitle("shuvcode") return } // Truncate title to 40 chars max const title = session.title.length > 40 ? session.title.slice(0, 37) + "..." : session.title - renderer.setTerminalTitle(`OC | ${title}`) + renderer.setTerminalTitle(`shuv | ${title}`) } }) @@ -300,6 +304,7 @@ function App() { dialog.clear() }, }, + { title: "Switch model", value: "model.list", @@ -365,6 +370,22 @@ function App() { dialog.replace(() => ) }, }, + { + title: "List tools", + value: "tool.list", + category: "Agent", + onSelect: () => { + dialog.replace(() => ) + }, + }, + { + title: "Toggle IDEs", + value: "ide.list", + category: "Agent", + onSelect: () => { + dialog.replace(() => ) + }, + }, { title: "Agent cycle", value: "agent.cycle", @@ -430,6 +451,31 @@ function App() { }, category: "System", }, + { + title: "Toggle transparency", + value: "theme.transparency", + onSelect: (dialog) => { + setTransparent(!transparent()) + dialog.clear() + }, + category: "System", + }, + { + title: "Change spinner style", + value: "spinner.style", + category: "System", + onSelect: () => { + dialog.replace(() => ) + }, + }, + { + title: "Change spinner interval", + value: "spinner.interval", + category: "System", + onSelect: () => { + dialog.replace(() => ) + }, + }, { title: "Help", value: "help.show", @@ -596,7 +642,7 @@ function App() { toast.show({ variant: "success", title: "Update Complete", - message: `OpenCode updated to v${evt.properties.version}`, + message: `shuvcode updated to v${evt.properties.version}`, duration: 5000, }) }) @@ -605,7 +651,7 @@ function App() { toast.show({ variant: "info", title: "Update Available", - message: `OpenCode v${evt.properties.version} is available. Run 'opencode upgrade' to update manually.`, + message: `shuvcode v${evt.properties.version} is available. Run 'shuvcode upgrade' to update manually.`, duration: 10000, }) }) diff --git a/packages/opencode/src/cli/cmd/tui/attach.ts b/packages/opencode/src/cli/cmd/tui/attach.ts index 561a8ced68d..c1c2c817012 100644 --- a/packages/opencode/src/cli/cmd/tui/attach.ts +++ b/packages/opencode/src/cli/cmd/tui/attach.ts @@ -1,3 +1,4 @@ +import path from "path" import { cmd } from "../cmd" import { tui } from "./app" @@ -21,12 +22,12 @@ export const AttachCommand = cmd({ describe: "session id to continue", }), handler: async (args) => { - if (args.dir) process.chdir(args.dir) - const directory = process.cwd() + const directory = args.dir ? path.resolve(args.dir) : process.cwd() + if (args.dir) process.chdir(directory) await tui({ url: args.url, - args: { sessionID: args.session }, directory, + args: { sessionID: args.session }, }) }, }) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index d19e93188b2..f7941baa2b1 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -27,7 +27,9 @@ function init() { const dialog = useDialog() const keybind = useKeybind() const options = createMemo(() => { - const all = registrations().flatMap((x) => x()) + const all = registrations() + .flatMap((x) => x()) + .filter((x) => !!x) const suggested = all.filter((x) => x.suggested) return [ ...suggested.map((x) => ({ diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-ide.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-ide.tsx new file mode 100644 index 00000000000..8998f6f5a0b --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-ide.tsx @@ -0,0 +1,76 @@ +import { createMemo, createSignal } from "solid-js" +import { useLocal } from "@tui/context/local" +import { useSync } from "@tui/context/sync" +import { map, pipe, entries, sortBy } from "remeda" +import { DialogSelect, type DialogSelectRef, type DialogSelectOption } from "@tui/ui/dialog-select" +import { useTheme } from "../context/theme" +import { Keybind } from "@/util/keybind" +import { TextAttributes } from "@opentui/core" + +function Status(props: { connected: boolean; loading: boolean }) { + const { theme } = useTheme() + if (props.loading) { + return ⋯ Loading + } + if (props.connected) { + return ✓ Connected + } + return ○ Disconnected +} + +export function DialogIde() { + const local = useLocal() + const sync = useSync() + const [, setRef] = createSignal>() + const [loading, setLoading] = createSignal(null) + + const options = createMemo(() => { + const ideData = sync.data.ide + const loadingIde = loading() + const projectDir = process.cwd() + + return pipe( + ideData ?? {}, + entries(), + sortBy( + ([key]) => { + const folders = local.ide.getWorkspaceFolders(key) + // Exact match - highest priority + if (folders.some((folder: string) => folder === projectDir)) return 0 + // IDE workspace contains current directory (we're in a subdirectory of IDE workspace) + if (folders.some((folder: string) => projectDir.startsWith(folder + "/"))) return 1 + return 2 + }, + ([, status]) => status.name, + ), + map(([key, status]) => { + return { + value: key, + title: status.name, + description: local.ide.getWorkspaceFolders(key)[0], + footer: , + category: undefined, + } + }), + ) + }) + + const keybinds = createMemo(() => [ + { + keybind: Keybind.parse("space")[0], + title: "toggle", + onTrigger: async (option: DialogSelectOption) => { + if (loading() !== null) return + + setLoading(option.value) + try { + await local.ide.toggle(option.value) + } finally { + setLoading(null) + } + }, + }, + ]) + + return {}} /> +} diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index 07de4d47200..6edd3d4d71c 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -9,6 +9,7 @@ import { useTheme } from "../context/theme" import { useSDK } from "../context/sdk" import { DialogSessionRename } from "./dialog-session-rename" import { useKV } from "../context/kv" +import { getSpinnerFrame } from "../util/spinners" import { createDebouncedSignal } from "../util/signal" import "opentui-spinner/solid" @@ -33,8 +34,6 @@ export function DialogSessionList() { const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined)) - const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] - const sessions = createMemo(() => searchResults() ?? sync.data.session) const options = createMemo(() => { @@ -59,7 +58,7 @@ export function DialogSessionList() { footer: Locale.time(x.time.updated), gutter: isWorking ? ( [⋯]}> - + {getSpinnerFrame()} ) : undefined, } diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-spinner.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-spinner.tsx new file mode 100644 index 00000000000..29ead6623b2 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-spinner.tsx @@ -0,0 +1,154 @@ +import { DialogSelect, type DialogSelectRef } from "../ui/dialog-select" +import { useTheme } from "../context/theme" +import { useDialog } from "../ui/dialog" +import { createEffect, createMemo, createSignal, on, onCleanup } from "solid-js" +import { + SPINNERS, + getSpinnerKeys, + getSpinnerDisplayName, + getSpinnerStyle, + setSpinnerStyle, + getSpinnerInterval, + setSpinnerInterval, + DEFAULT_SPINNER_KEY, + DEFAULT_SPINNER_INTERVAL_MS, + SPINNER_INTERVAL_PRESETS, +} from "../util/spinners" +import { useKV } from "../context/kv" + +export function DialogSpinnerInterval() { + const { theme } = useTheme() + const dialog = useDialog() + const kv = useKV() + const initial = getSpinnerInterval() + + // Create a signal for the preview animation + const [previewIndex, setPreviewIndex] = createSignal(0) + const [selectedInterval, setSelectedInterval] = createSignal(initial) + + // Animate preview using the selected interval + createEffect(() => { + const intervalMs = selectedInterval() + const interval = setInterval(() => { + const frames = SPINNERS[getSpinnerStyle()] || SPINNERS[DEFAULT_SPINNER_KEY] + setPreviewIndex((prev) => (prev + 1) % frames.length) + }, intervalMs) + onCleanup(() => clearInterval(interval)) + }) + + // Reset preview index when selection changes + createEffect( + on(selectedInterval, () => { + setPreviewIndex(0) + }), + ) + + const currentFrame = createMemo(() => { + const frames = SPINNERS[getSpinnerStyle()] || SPINNERS[DEFAULT_SPINNER_KEY] + return frames[previewIndex()] + }) + + const options = SPINNER_INTERVAL_PRESETS.map((preset) => ({ + title: preset.label, + value: preset.value, + })) + + return ( + <> + + + Preview: {currentFrame()} + + + { + setSelectedInterval(opt.value) + }} + onSelect={(opt) => { + setSpinnerInterval(opt.value) + kv.set("spinner_interval", opt.value) + dialog.clear() + }} + /> + + ) +} + +export function DialogSpinnerList() { + const { theme } = useTheme() + const dialog = useDialog() + const kv = useKV() + let ref: DialogSelectRef + const initial = getSpinnerStyle() + + // Create a signal for the preview animation + const [previewIndex, setPreviewIndex] = createSignal(0) + const [selectedKey, setSelectedKey] = createSignal(initial) + + // Animate preview using the current interval setting + createEffect(() => { + const intervalMs = getSpinnerInterval() + const interval = setInterval(() => { + const frames = SPINNERS[selectedKey()] || SPINNERS[DEFAULT_SPINNER_KEY] + setPreviewIndex((prev) => (prev + 1) % frames.length) + }, intervalMs) + onCleanup(() => clearInterval(interval)) + }) + + // Reset preview index when selection changes + createEffect( + on(selectedKey, () => { + setPreviewIndex(0) + }), + ) + + const currentFrame = createMemo(() => { + const frames = SPINNERS[selectedKey()] || SPINNERS[DEFAULT_SPINNER_KEY] + return frames[previewIndex()] + }) + + const options = getSpinnerKeys().map((key) => ({ + title: getSpinnerDisplayName(key), + value: key, + description: SPINNERS[key].slice(0, 3).join(" "), + })) + + return ( + <> + + + Preview: {currentFrame()} + + + { + setSelectedKey(opt.value) + }} + onSelect={(opt) => { + setSpinnerStyle(opt.value) + kv.set("spinner_style", opt.value) + dialog.clear() + }} + ref={(r) => { + ref = r + }} + onFilter={(query) => { + if (query.length === 0) { + setSelectedKey(initial) + return + } + const first = ref.filtered[0] + if (first) setSelectedKey(first.value) + }} + /> + + ) +} diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-tools.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-tools.tsx new file mode 100644 index 00000000000..78c26151a30 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-tools.tsx @@ -0,0 +1,44 @@ +import { createMemo, createResource } from "solid-js" +import { map, pipe, sortBy } from "remeda" +import { DialogSelect, type DialogSelectOption } from "@tui/ui/dialog-select" +import { useSDK } from "@tui/context/sdk" + +type ToolInfo = { + id: string + enabled: boolean +} + +export function DialogTools() { + const sdk = useSDK() + + const [tools] = createResource(async () => { + const response = await fetch(`${sdk.url}/tool/list`) + if (!response.ok) return [] + return (await response.json()) as ToolInfo[] + }) + + const options = createMemo((): DialogSelectOption[] => { + const toolList = tools() ?? [] + + return pipe( + toolList, + sortBy((t) => t.id), + map((t) => ({ + value: t.id, + title: t.id, + footer: t.enabled ? undefined : "disabled", + category: undefined, + })), + ) + }) + + return ( + { + // Don't close on select, only on escape + }} + /> + ) +} diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index d1be06a7f25..fdb34d42098 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -2,8 +2,10 @@ import { TextAttributes } from "@opentui/core" import { For } from "solid-js" import { useTheme } from "@tui/context/theme" -const LOGO_LEFT = [` `, `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, `█░░█ █░░█ █▀▀▀ █░░█`, `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`] +// "shuv" +const LOGO_LEFT = [` ▄ `, `█▀▀▀ █▀▀█ █ █ █ █`, `▀▀▀█ █░░█ █░░█ █░░█`, `▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀ `] +// "code" const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█░░░ █░░█ █░░█ █▀▀▀`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`] export function Logo() { diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 8a6db34242a..5b82ac98973 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -5,6 +5,7 @@ import { createMemo, createResource, createEffect, onMount, onCleanup, For, Show import { createStore } from "solid-js/store" import { useSDK } from "@tui/context/sdk" import { useSync } from "@tui/context/sync" +import { useLocal } from "@tui/context/local" import { useTheme, selectedForeground } from "@tui/context/theme" import { SplitBorder } from "@tui/component/border" import { useCommandDialog } from "@tui/component/dialog-command" @@ -75,6 +76,7 @@ export function Autocomplete(props: { }) { const sdk = useSDK() const sync = useSync() + const local = useLocal() const command = useCommandDialog() const { theme } = useTheme() const dimensions = useTerminalDimensions() @@ -312,10 +314,14 @@ export function Autocomplete(props: { const commands = createMemo((): AutocompleteOption[] => { const results: AutocompleteOption[] = [] const s = session() + for (const command of sync.data.command) { + if (command.sessionOnly && !s) continue + results.push({ display: "/" + command.name + (command.mcp ? " (MCP)" : ""), description: command.description, + aliases: command.aliases?.map((a) => "/" + a), onSelect: () => { const newText = "/" + command.name + " " const cursor = props.input().logicalCursor @@ -425,6 +431,16 @@ export function Autocomplete(props: { description: "toggle MCPs", onSelect: () => command.trigger("mcp.list"), }, + { + display: "/tools", + description: "list tools", + onSelect: () => command.trigger("tool.list"), + }, + { + display: "/ide", + description: "toggle IDEs", + onSelect: () => command.trigger("ide.list"), + }, { display: "/theme", description: "toggle theme", @@ -600,9 +616,8 @@ export function Autocomplete(props: { onKeyDown(e: KeyEvent) { if (store.visible) { const name = e.name?.toLowerCase() - const ctrlOnly = e.ctrl && !e.meta && !e.shift - const isNavUp = name === "up" || (ctrlOnly && name === "p") - const isNavDown = name === "down" || (ctrlOnly && name === "n") + const isNavUp = name === "up" + const isNavDown = name === "down" if (isNavUp) { move(-1) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 4558914cb7e..b30c2db9f6e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -19,11 +19,13 @@ import { useRenderer } from "@opentui/solid" import { Editor } from "@tui/util/editor" import { useExit } from "../../context/exit" import { Clipboard } from "../../util/clipboard" +import { parseUriList } from "../../util/uri" import type { FilePart } from "@opencode-ai/sdk/v2" import { TuiEvent } from "../../event" import { iife } from "@/util/iife" import { Locale } from "@/util/locale" -import { createColors, createFrames } from "../../ui/spinner.ts" +import { getSpinnerFrame } from "../../util/spinners" +import { createColors, createFrames } from "../../ui/spinner" import { useDialog } from "@tui/ui/dialog" import { DialogProvider as DialogProviderConnect } from "../dialog-provider" import { DialogAlert } from "../../ui/dialog-alert" @@ -36,6 +38,7 @@ export type PromptProps = { visible?: boolean disabled?: boolean onSubmit?: () => void + onSearchToggle?: () => void ref?: (ref: PromptRef) => void hint?: JSX.Element showPlaceholder?: boolean @@ -242,9 +245,10 @@ export function Prompt(props: PromptProps) { const nonTextParts = store.prompt.parts.filter((p) => p.type !== "text") const value = trigger === "prompt" ? "" : text - const content = await Editor.open({ value, renderer }) - if (!content) return + const result = await Editor.open({ value, renderer }) + if (!result.ok) return + const content = result.content input.setText(content) // Update positions for nonTextParts based on their location in new content @@ -611,6 +615,22 @@ export function Prompt(props: PromptProps) { } const exit = useExit() + let lastExitAttempt = 0 + + async function tryExit() { + const now = Date.now() + if (now - lastExitAttempt < 2000) { + await exit() + return + } + lastExitAttempt = now + toast.show({ + variant: "warning", + message: "Press again to exit", + duration: 2000, + }) + } + function pasteText(text: string, virtualText: string) { const currentOffset = input.visualCursor.offset const extmarkStart = currentOffset @@ -701,6 +721,7 @@ export function Prompt(props: PromptProps) { return !!current }) + const spinnerColor = createMemo(() => local.agent.color(local.agent.current().name)) const spinnerDef = createMemo(() => { const color = local.agent.color(local.agent.current().name) return { @@ -708,14 +729,12 @@ export function Prompt(props: PromptProps) { color, style: "blocks", inactiveFactor: 0.6, - // enableFading: false, minAlpha: 0.3, }), color: createColors({ color, style: "blocks", inactiveFactor: 0.6, - // enableFading: false, minAlpha: 0.3, }), } @@ -808,7 +827,7 @@ export function Prompt(props: PromptProps) { } if (keybind.match("app_exit", e)) { if (store.prompt.input === "") { - await exit() + await tryExit() // Don't preventDefault - let textarea potentially handle the event e.preventDefault() return @@ -869,6 +888,39 @@ export function Prompt(props: PromptProps) { return } + // Handle file:// URIs or text/uri-list (common for drag-and-drop on Linux) + if (pastedContent.includes("file://")) { + const paths = parseUriList(pastedContent) + if (paths.length > 0) { + let handled = false + for (const path of paths) { + try { + const file = Bun.file(path) + if (file.type.startsWith("image/")) { + const content = await file + .arrayBuffer() + .then((buffer) => Buffer.from(buffer).toString("base64")) + .catch(() => {}) + if (content) { + await pasteImage({ + filename: file.name, + mime: file.type, + content, + }) + handled = true + continue + } + } + } catch {} + } + + if (handled) { + event.preventDefault() + return + } + } + } + // trim ' from the beginning and end of the pasted content. just // ' and nothing else const filepath = pastedContent.replace(/^'+|'+$/g, "").replace(/\\ /g, " ") diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/search.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/search.tsx new file mode 100644 index 00000000000..388c3604199 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/search.tsx @@ -0,0 +1,241 @@ +import { BoxRenderable, TextareaRenderable, type KeyBinding, RGBA } from "@opentui/core" +import { createEffect, createMemo, onMount, Show } from "solid-js" +import { useTheme } from "@tui/context/theme" +import { EmptyBorder } from "@tui/component/border" +import { createStore } from "solid-js/store" +import { useKeybind } from "@tui/context/keybind" +import { useLocal } from "@tui/context/local" +import { useExit } from "../../context/exit" +import { useToast } from "../../ui/toast" + +export type SearchInputProps = { + disabled?: boolean + onSubmit?: (query: string) => void + onExit?: () => void + onInput?: (query: string) => void + onNext?: () => void + onPrevious?: () => void + matchInfo?: { current: number; total: number } + sessionID?: string + ref?: (ref: SearchInputRef) => void + placeholder?: string +} + +export type SearchInputRef = { + focused: boolean + reset(): void + blur(): void + focus(): void + getValue(): string +} + +export function SearchInput(props: SearchInputProps) { + let input: TextareaRenderable + let anchor: BoxRenderable + + const exit = useExit() + const keybind = useKeybind() + const local = useLocal() + const toast = useToast() + const { theme } = useTheme() + + let lastExitAttempt = 0 + + async function tryExit() { + const now = Date.now() + if (now - lastExitAttempt < 2000) { + await exit() + return + } + lastExitAttempt = now + toast.show({ + variant: "warning", + message: "Press again to exit", + duration: 2000, + }) + } + + const highlight = createMemo(() => { + const agent = local.agent.current() + if (agent?.color) return RGBA.fromHex(agent.color) + const agents = local.agent.list() + const index = agents.findIndex((x) => x.name === "search") + const colors = [theme.secondary, theme.accent, theme.success, theme.warning, theme.primary, theme.error] + if (index === -1) return colors[0] + return colors[index % colors.length] + }) + + const textareaKeybindings = createMemo(() => { + const submitBindings = keybind.all.input_submit || [] + return [ + { name: "return", action: "submit" }, + ...submitBindings.map((binding) => ({ + name: binding.name, + ctrl: binding.ctrl || undefined, + meta: binding.meta || undefined, + shift: binding.shift || undefined, + action: "submit" as const, + })), + ] satisfies KeyBinding[] + }) + + const [store, setStore] = createStore<{ + input: string + }>({ + input: "", + }) + + createEffect(() => { + if (props.disabled) input.cursorColor = theme.backgroundElement + if (!props.disabled) input.cursorColor = theme.primary + }) + + props.ref?.({ + get focused() { + return input.focused + }, + focus() { + input.focus() + }, + blur() { + input.blur() + }, + reset() { + input.clear() + setStore("input", "") + }, + getValue() { + return store.input + }, + }) + + function submit() { + if (props.disabled) return + // On Enter, navigate to next match instead of clearing + props.onNext?.() + } + + onMount(() => { + input.focus() + }) + + return ( + <> + (anchor = r)}> + + +