diff --git a/.github/workflows/auto-docs.yml b/.github/workflows/auto-docs.yml new file mode 100644 index 00000000000..4364ee87480 --- /dev/null +++ b/.github/workflows/auto-docs.yml @@ -0,0 +1,35 @@ +name: Trigger webhook for feat PRs + +on: + pull_request: + types: [closed] + +jobs: + call-webhook: + if: > + github.event.pull_request.merged == true && + (startsWith(github.event.pull_request.title, 'feat:') || + startsWith(github.event.pull_request.title, 'feat(')) + runs-on: ubuntu-latest + steps: + - name: Send webhook safely + run: | + payload=$(jq -n \ + --arg repo "${GITHUB_REPOSITORY}" \ + --arg pr_number "${{ github.event.pull_request.number }}" \ + --arg title "${{ github.event.pull_request.title }}" \ + --arg body "${{ github.event.pull_request.body }}" \ + --arg author "${{ github.event.pull_request.user.login }}" \ + --arg merged_at "${{ github.event.pull_request.merged_at }}" \ + '{ + repo: $repo, + pr_number: $pr_number, + title: $title, + description: $body, + author: $author, + merged_at: $merged_at + }' + ) + curl --fail-with-body -X POST "${{ secrets.DOC_WEBHOOK_URL }}" \ + -H "Content-Type: application/json" \ + --data-raw "$payload" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 178b6ba582f..aa6bcfa45c3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -240,11 +240,90 @@ jobs: # APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} # APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8 + # kilocode_change start + # Smoke test disabled as a release gate due to infrastructure issues. + # The job is skipped via `if: false` so it no longer blocks publishing. + # Re-enable by restoring the original `if:` condition and uncommenting + # `- smoke-test` in the publish job's `needs` list below. + smoke-test: + name: Smoke Test (pre-publish gate) [DISABLED] + needs: + - version + - build-cli + if: false # was: github.repository == 'Kilo-Org/kilocode' + runs-on: ubuntu-24.04 + steps: + - name: Trigger kilo-bench smoke test + id: trigger + env: + GH_TOKEN: ${{ secrets.BENCH_GITHUB_TOKEN }} + run: | + BEFORE=$(date -u -d '60 seconds ago' +%Y-%m-%dT%H:%M:%SZ) + + gh api repos/Kilo-Org/kilo-bench/dispatches \ + --method POST \ + -f event_type=smoke-test \ + -f 'client_payload[release_tag]=${{ needs.version.outputs.tag }}' \ + -f 'client_payload[source_run_id]=${{ github.run_id }}' + + # Poll for the run created after our dispatch timestamp. + # The dispatch API returns no run ID, so we query by created time + # and pick the oldest match to avoid grabbing an unrelated run. + echo "Waiting for smoke-test run to appear (dispatched after $BEFORE)..." + for attempt in $(seq 1 30); do + RUN_ID=$(gh api \ + "repos/Kilo-Org/kilo-bench/actions/workflows/smoke-test.yml/runs?event=repository_dispatch&created=>=$BEFORE" \ + --jq '.workflow_runs | sort_by(.created_at) | .[0].id // empty') + + if [[ -n "$RUN_ID" && "$RUN_ID" != "null" ]]; then + echo "run_id=$RUN_ID" >> "$GITHUB_OUTPUT" + echo "::notice::Smoke test run: https://github.com/Kilo-Org/kilo-bench/actions/runs/$RUN_ID" + exit 0 + fi + + echo " attempt $attempt: run not yet registered, retrying in 10s..." + sleep 10 + done + + echo "::error::Smoke test run did not appear within 5 minutes after dispatch." + exit 1 + + - name: Wait for smoke test to complete + env: + GH_TOKEN: ${{ secrets.BENCH_GITHUB_TOKEN }} + run: | + RUN_ID="${{ steps.trigger.outputs.run_id }}" + echo "Waiting for run $RUN_ID..." + + for i in $(seq 1 60); do + CONCLUSION=$(gh run view "$RUN_ID" \ + --repo Kilo-Org/kilo-bench \ + --json conclusion \ + --jq '.conclusion') + + echo " attempt $i: $CONCLUSION" + + if [[ "$CONCLUSION" == "success" ]]; then + echo "::notice::Smoke test passed." + exit 0 + elif [[ "$CONCLUSION" != "null" && "$CONCLUSION" != "" ]]; then + echo "::error::Smoke test failed with conclusion: $CONCLUSION" + echo "See: https://github.com/Kilo-Org/kilo-bench/actions/runs/$RUN_ID" + exit 1 + fi + + sleep 30 + done + + echo "::error::Smoke test did not complete within 30 minutes." + exit 1 + # kilocode_change end publish: needs: - version - build-cli - build-vscode + # - smoke-test # disabled: infrastructure issues (see smoke-test job comment) # - build-tauri runs-on: ubuntu-24.04 steps: diff --git a/.github/workflows/source-check-links.yml b/.github/workflows/source-check-links.yml new file mode 100644 index 00000000000..60df85b4b54 --- /dev/null +++ b/.github/workflows/source-check-links.yml @@ -0,0 +1,24 @@ +name: Check Source Links + +on: + pull_request: + paths: + - "packages/kilo-vscode/src/**" + - "packages/kilo-vscode/webview-ui/**" + - "packages/opencode/src/**" + - "packages/kilo-docs/source-links.md" + - "script/extract-source-links.ts" + - ".github/workflows/source-check-links.yml" + workflow_dispatch: # Allow manual trigger + +jobs: + source-links-freshness: + if: github.repository == 'Kilo-Org/kilocode' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v2 + + - name: Check source-links.md is up to date + run: bun run script/extract-source-links.ts --check diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml new file mode 100644 index 00000000000..9cd606324a1 --- /dev/null +++ b/.github/workflows/storybook.yml @@ -0,0 +1,39 @@ +name: storybook + +on: + push: + branches: [dev] + paths: + - ".github/workflows/storybook.yml" + - "package.json" + - "bun.lock" + - "packages/storybook/**" + - "packages/ui/**" + pull_request: + branches: [dev] + paths: + - ".github/workflows/storybook.yml" + - "package.json" + - "bun.lock" + - "packages/storybook/**" + - "packages/ui/**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + if: false + name: storybook build + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Build Storybook + run: bun --cwd packages/storybook build diff --git a/.github/workflows/test-vscode.yml b/.github/workflows/test-vscode.yml index 9ec1df4f442..272879f2e0b 100644 --- a/.github/workflows/test-vscode.yml +++ b/.github/workflows/test-vscode.yml @@ -42,3 +42,7 @@ jobs: - name: Check for dead code (knip) working-directory: packages/kilo-vscode run: bun run knip + + - name: Check for kilocode_change markers + working-directory: packages/kilo-vscode + run: bun run check-kilocode-change diff --git a/.github/workflows/visual-regression.yml b/.github/workflows/visual-regression.yml index b295678f4c5..369da658564 100644 --- a/.github/workflows/visual-regression.yml +++ b/.github/workflows/visual-regression.yml @@ -25,6 +25,8 @@ jobs: - "packages/kilo-vscode/webview-ui/**" - "packages/kilo-vscode/.storybook/**" - "packages/kilo-vscode/tests/visual-regression*" + - "packages/kilo-vscode/tests/permission-dock-dropdown*" + - "packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/**" - ".github/workflows/visual-regression.yml" - name: Check if PR is from a fork id: fork-check @@ -181,7 +183,7 @@ jobs: else git commit -m "chore: update visual regression baselines" git lfs push --all origin - git push + git push --no-verify echo "changed=true" >> "$GITHUB_OUTPUT" fi @@ -302,10 +304,42 @@ jobs: " working-directory: packages/kilo-vscode + - name: Remove stale baselines for permission-dock-dropdown tests + run: | + node -e " + const fs = require('fs'), path = require('path'); + const specPath = 'tests/permission-dock-dropdown.spec.ts'; + const expected = new Set(); + if (fs.existsSync(specPath)) { + const spec = fs.readFileSync(specPath, 'utf8'); + const re = /toHaveScreenshot\(\[([^\]]+)\]\)/g; + let m; + while ((m = re.exec(spec)) !== null) { + const parts = m[1].split(',').map(s => s.trim().replace(/[\"']/g, '')); + expected.add(parts.join('/').replace(/\.png$/, '-chromium-linux.png')); + } + } + const dir = 'tests/permission-dock-dropdown.spec.ts-snapshots'; + if (!fs.existsSync(dir)) process.exit(0); + for (const sub of fs.readdirSync(dir)) { + const sdir = path.join(dir, sub); + if (!fs.statSync(sdir).isDirectory()) continue; + for (const file of fs.readdirSync(sdir)) { + const rel = sub + '/' + file; + if (file.endsWith('.png') && !expected.has(rel)) { + console.log('Removing stale baseline:', rel); + fs.unlinkSync(path.join(sdir, file)); + } + } + } + " + working-directory: packages/kilo-vscode + - name: Check for baseline changes (fork PRs) if: needs.check-paths.outputs.is_fork == 'true' run: | git add packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/ + [ -d packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots ] && git add packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/ if git diff --cached --quiet; then echo "No visual regression detected." else @@ -320,6 +354,7 @@ jobs: if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit-vscode.outputs.is_baseline_update == 'true' run: | git add packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/ + [ -d packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots ] && git add packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/ if git diff --cached --quiet; then echo "Baselines are stable after auto-update." else @@ -339,13 +374,14 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/ + [ -d packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots ] && git add packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/ if git diff --cached --quiet; then echo "No new baselines — nothing to commit." echo "changed=false" >> "$GITHUB_OUTPUT" else git commit -m "chore: update kilo-vscode visual regression baselines" git lfs push --all origin - git push + git push --no-verify echo "changed=true" >> "$GITHUB_OUTPUT" fi diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc index cc490ac790f..30c4d882b90 100644 --- a/.opencode/opencode.jsonc +++ b/.opencode/opencode.jsonc @@ -8,6 +8,11 @@ "options": {}, }, }, + "permission": { + "edit": { + "packages/opencode/migration/*": "deny", + }, + }, "mcp": {}, "tools": { "github-triage": false, diff --git a/.opencode/tool/github-pr-search.txt b/.opencode/tool/github-pr-search.txt index 28d8643f13c..1b658e71c43 100644 --- a/.opencode/tool/github-pr-search.txt +++ b/.opencode/tool/github-pr-search.txt @@ -1,6 +1,6 @@ Use this tool to search GitHub pull requests by title and description. -This tool searches PRs in the sst/opencode repository and returns LLM-friendly results including: +This tool searches PRs in the anomalyco/opencode repository and returns LLM-friendly results including: - PR number and title - Author - State (open/closed/merged) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index daa91bc53e5..4aabf87953f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -65,6 +65,20 @@ }, "problemMatcher": [] }, + { + "label": "VSCode - Install", + "type": "shell", + "command": "bun", + "args": ["install", "--frozen-lockfile"], + "group": "build", + "presentation": { + "reveal": "silent" + }, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + }, { "label": "VSCode - Compile", "type": "shell", @@ -77,6 +91,7 @@ "options": { "cwd": "${workspaceFolder}/packages/kilo-vscode" }, + "dependsOn": ["VSCode - Install"], "problemMatcher": ["$tsc", "$eslint-stylish"] }, { @@ -101,9 +116,27 @@ "problemMatcher": [] }, { - "label": "install-dev-extension", + "label": "VSCode - DevSnapshot - Build", "type": "shell", - "command": "bun script/install-dev-extension.ts", + "command": "bun run snapshot:build", + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "options": { + "cwd": "${workspaceFolder}/packages/kilo-vscode" + }, + "problemMatcher": [] + }, + { + "label": "VSCode - DevSnapshot - Install", + "type": "shell", + "command": "bun run snapshot:install", "group": "build", "presentation": { "echo": true, diff --git a/AGENTS.md b/AGENTS.md index c0262af58b8..a8323860822 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,11 +10,14 @@ Kilo CLI is an open source AI coding agent that generates code from natural lang ## Build and Dev - **Dev**: `bun run dev` (runs from root) or `bun run --cwd packages/opencode --conditions=browser src/index.ts` +- **Extension**: `bun run extension` (build + launch VS Code with the extension in dev mode). Pass `--no-build` to skip the build. - **Typecheck**: `bun turbo typecheck` (uses `tsgo`, not `tsc`) - **Test**: `bun test` from `packages/opencode/` (NOT from root -- root blocks tests) - **Single test**: `bun test test/tool/tool.test.ts` from `packages/opencode/` - **SDK regen**: After changing server endpoints in `packages/opencode/src/server/`, run `./script/generate.ts` from root to regenerate `packages/sdk/js/` - **Knip** (unused exports): `bun run knip` from `packages/kilo-vscode/`. CI runs this — all exported types/functions must be imported somewhere. Remove or unexport unused exports before pushing. +- **Source links**: After adding or changing URLs in `packages/kilo-vscode/`, `packages/kilo-vscode/webview-ui/`, or `packages/opencode/src/`, run `bun run script/extract-source-links.ts` from the repo root and commit the updated `packages/kilo-docs/source-links.md`. CI runs this check — the build fails if the file is stale. +- **kilocode_change check**: `bun run check-kilocode-change` from `packages/kilo-vscode/`. CI runs this — `kilocode_change` is a marker for upstream merge conflicts and must not appear in `packages/kilo-vscode/` or `packages/kilo-ui/` (these are entirely Kilo Code additions). Remove the markers before pushing. ## Products @@ -162,6 +165,10 @@ const bazFoo = 3 You MUST avoid using `mocks` as much as possible. Tests MUST test actual implementation, do not duplicate logic into a test. +## Commit Conventions + +[Conventional Commits](https://www.conventionalcommits.org/) with scopes matching packages: `vscode`, `cli`, `agent-manager`, `sdk`, `ui`, `i18n`, `kilo-docs`, `gateway`, `telemetry`, `desktop`. Omit scope when spanning multiple packages. + ## Fork Merge Process Kilo CLI is a fork of [opencode](https://github.com/anomalyco/opencode). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed0cb83d8af..65565b37ab7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,6 +24,16 @@ The Kilo Community is [on Discord](https://kilo.ai/discord). bun dev ``` +### Developing the VS Code Extension + +Build and launch the extension in an isolated VS Code instance: + +```bash +bun run extension # Build + launch in dev mode +``` + +This auto-detects VS Code on macOS, Linux, and Windows. Override with `--app-path PATH` or `VSCODE_EXEC_PATH`. Use `--insiders` to prefer Insiders, `--workspace PATH` to open a specific folder, or `--clean` to reset cached state. + ### Running against a different directory By default, `bun dev` runs Kilo CLI in the `packages/opencode` directory. To run it against a different directory or repository: @@ -70,6 +80,26 @@ kilo serve # Start headless API server kilo web # Start server + open web interface ``` +### Testing with a local backend + +To point the CLI at a local backend (e.g., a locally running Kilo API server on port 3000), set the `KILO_API_URL` environment variable: + +```bash +KILO_API_URL=http://localhost:3000 bun dev +``` + +This redirects all gateway traffic (auth, model listing, provider routing, profile, etc.) to your local server. The default is `https://api.kilo.ai`. + +There are also optional overrides for other services: + +| Variable | Default | Purpose | +| ------------------------- | -------------------------------- | ----------------------------------------- | +| `KILO_API_URL` | `https://api.kilo.ai` | Kilo API (gateway, auth, models, profile) | +| `KILO_SESSION_INGEST_URL` | `https://ingest.kilosessions.ai` | Session export / cloud sync | +| `KILO_MODELS_URL` | `https://models.dev` | Model metadata | + +> **VS Code:** The repo includes a "VSCode - Run Extension (Local Backend)" launch config in `.vscode/launch.json` that sets `KILO_API_URL=http://localhost:3000` automatically. + ### Pull Request Expectations - **Issue First Policy:** All PRs must reference an existing issue. diff --git a/RELEASING.md b/RELEASING.md index ee2e8b465f8..437d34b1926 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -34,7 +34,7 @@ The `publish.yml` workflow runs four jobs sequentially: - Builds native binaries for **all supported platforms and architectures**: - Linux: x64, arm64 (glibc and musl), plus baseline (non-AVX2) variants - macOS: x64, arm64, plus baseline variants - - Windows: x64, plus baseline variant + - Windows: x64 (plus baseline variant), arm64 - Patches ELF interpreters on Linux binaries for broad compatibility. - Creates platform archives (`.tar.gz` for Linux, `.zip` for macOS/Windows) and uploads them to the draft GitHub Release. - Uploads the `dist/` directory as a workflow artifact (`kilo-cli`) for subsequent jobs. @@ -43,7 +43,7 @@ The `publish.yml` workflow runs four jobs sequentially: - Downloads the CLI artifacts from the previous job. - Runs `packages/kilo-vscode/script/build.ts` to build VSIX packages for all target platforms: - - `linux-x64`, `linux-arm64`, `alpine-x64`, `alpine-arm64`, `darwin-x64`, `darwin-arm64`, `win32-x64` + - `linux-x64`, `linux-arm64`, `alpine-x64`, `alpine-arm64`, `darwin-x64`, `darwin-arm64`, `win32-x64`, `win32-arm64` - Each VSIX bundles the platform-specific CLI binary. - Uploads the VSIX files as a workflow artifact (`kilo-vscode`). diff --git a/bun.lock b/bun.lock index a3a18be5fa2..1b88266b26c 100644 --- a/bun.lock +++ b/bun.lock @@ -8,6 +8,7 @@ "@aws-sdk/client-s3": "3.933.0", "@kilocode/plugin": "workspace:*", "@kilocode/sdk": "workspace:*", + "@morphllm/morphsdk": "0.2.141", "@opencode-ai/script": "workspace:*", "typescript": "catalog:", }, @@ -15,17 +16,18 @@ "@actions/artifact": "5.0.1", "@tsconfig/bun": "catalog:", "@types/mime-types": "3.0.1", + "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.5.6", + "turbo": "2.8.13", }, }, "packages/app": { "name": "@opencode-ai/app", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-ui": "workspace:*", @@ -48,7 +50,7 @@ "@thisbeyond/solid-dnd": "0.7.5", "diff": "catalog:", "fuzzysort": "catalog:", - "ghostty-web": "0.4.0", + "ghostty-web": "github:anomalyco/ghostty-web#main", "luxon": "catalog:", "marked": "catalog:", "marked-shiki": "catalog:", @@ -77,7 +79,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -110,7 +112,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "7.0.46", + "version": "7.1.3", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -140,7 +142,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -169,8 +171,11 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { + "@ai-sdk/anthropic": "2.0.65", + "@ai-sdk/openai": "2.0.89", + "@ai-sdk/openai-compatible": "1.0.32", "@clack/prompts": "1.0.0-alpha.1", "@kilocode/plugin": "workspace:*", "@kilocode/sdk": "workspace:*", @@ -201,7 +206,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.0.47", + "version": "7.1.3", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -211,7 +216,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "@opentelemetry/api": "1.9.0", @@ -231,17 +236,23 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@kobalte/core": "0.13.11", "@opencode-ai/util": "workspace:*", "@pierre/diffs": "catalog:", + "@solid-primitives/lifecycle": "0.1.2", "@solid-primitives/media": "2.3.3", "@solid-primitives/resize-observer": "2.1.5", + "@solid-primitives/rootless": "1.5.2", "lucide-solid": "0.576.0", + "motion": "12.34.5", + "motion-dom": "12.34.3", + "motion-utils": "12.29.2", + "strip-ansi": "7.1.2", }, "devDependencies": { - "@playwright/test": "1.58.2", + "@playwright/test": "1.57.0", "@storybook/addon-a11y": "10.2.10", "@storybook/addon-docs": "10.2.10", "@storybook/addon-themes": "10.2.10", @@ -260,7 +271,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-i18n": "workspace:*", @@ -271,6 +282,7 @@ "diff": "^7.0.0", "dotenv": "^16.4.7", "fastest-levenshtein": "^1.0.16", + "friendly-words": "1.3.1", "ignore": "^7.0.3", "js-tiktoken": "^1.0.18", "lru-cache": "^11.0.2", @@ -280,16 +292,17 @@ "solid-js": "^1.9.11", "uri-js": "^4.4.1", "web-tree-sitter": "^0.24.7", + "yaml": "2.8.2", "zod": "^3.24.2", }, "devDependencies": { - "@playwright/test": "1.58.2", + "@playwright/test": "1.57.0", "@storybook/addon-docs": "10.2.10", "@types/diff": "^6.0.0", "@types/mocha": "^10.0.10", "@types/node": "22.x", "@types/qrcode": "^1.5.6", - "@types/vscode": "^1.108.0", + "@types/vscode": "^1.105.1", "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.5.2", "@vscode/vsce": "^3.7.1", @@ -311,9 +324,10 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.0.47", + "version": "7.1.3", "bin": { - "opencode": "./bin/opencode", + "kilo": "./bin/kilo", + "kilocode": "./bin/kilo", }, "dependencies": { "@actions/core": "1.11.1", @@ -349,14 +363,15 @@ "@kilocode/plugin": "workspace:*", "@kilocode/sdk": "workspace:*", "@modelcontextprotocol/sdk": "1.25.2", + "@morphllm/morphsdk": "0.2.148", "@octokit/graphql": "9.0.2", "@octokit/rest": "catalog:", "@openauthjs/openauth": "catalog:", "@opencode-ai/script": "workspace:*", "@opencode-ai/util": "workspace:*", "@openrouter/ai-sdk-provider": "1.5.4", - "@opentui/core": "0.1.86", - "@opentui/solid": "0.1.86", + "@opentui/core": "0.1.87", + "@opentui/solid": "0.1.87", "@parcel/watcher": "2.5.1", "@pierre/diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -371,7 +386,7 @@ "clipboardy": "4.0.0", "decimal.js": "10.5.0", "diff": "catalog:", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "fuzzysort": "3.1.0", "glob": "13.0.5", "google-auth-library": "10.5.0", @@ -394,6 +409,7 @@ "ulid": "catalog:", "vscode-jsonrpc": "8.2.1", "web-tree-sitter": "0.25.10", + "which": "6.0.1", "xdg-basedir": "5.1.0", "yargs": "18.0.0", "zod": "catalog:", @@ -409,6 +425,7 @@ "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1", "@standard-schema/spec": "1.0.0", "@tsconfig/bun": "catalog:", @@ -416,10 +433,11 @@ "@types/bun": "catalog:", "@types/mime-types": "3.0.1", "@types/turndown": "5.0.5", + "@types/which": "3.0.4", "@types/yargs": "17.0.33", "@typescript/native-preview": "catalog:", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "typescript": "catalog:", "vscode-languageserver-types": "3.17.5", "why-is-node-running": "3.2.2", @@ -428,7 +446,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@kilocode/sdk": "workspace:*", "zod": "catalog:", @@ -442,14 +460,14 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.0.47", + "version": "7.1.3", "devDependencies": { "@types/bun": "catalog:", }, }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.0.47", + "version": "7.1.3", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -460,7 +478,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.0.47", + "version": "7.1.3", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -483,7 +501,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -494,6 +512,7 @@ "@solid-primitives/media": "2.3.3", "@solid-primitives/resize-observer": "2.1.3", "@solidjs/meta": "catalog:", + "@solidjs/router": "catalog:", "@typescript/native-preview": "catalog:", "dompurify": "3.3.1", "fuzzysort": "catalog:", @@ -529,7 +548,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "7.0.47", + "version": "7.1.3", "dependencies": { "zod": "catalog:", }, @@ -573,12 +592,12 @@ "@types/luxon": "3.7.1", "@types/node": "22.13.9", "@types/semver": "7.7.1", - "@typescript/native-preview": "7.0.0-dev.20251207.1", + "@typescript/native-preview": "7.0.0-dev.20260316.1", "ai": "5.0.124", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "fuzzysort": "3.1.0", "hono": "4.10.7", "hono-openapi": "1.1.2", @@ -694,23 +713,23 @@ "@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-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.12", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.996.9", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-0R7EKJBd19VGoYMrp7ozikwRh6KpapIO3T/Vf9tMrAVxrUNd5V+A6V1gxypY7iJv9GwVR1ZWL/nFt/m0KvcjIQ=="], + "@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.14", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.996.11", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-gvN2aWLe+uSzCB9ys/NcuJwWNCmBtPpP1Y6gAw8zJi772Glci6eTJ+Hvlyj3t838hoFbBvFUvz4eev7jW2a5Sw=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-MBAMW6YELzE1SdkOniqr51mrjapQUv8JXSGxtwRjQV0mwVDutVsn22OPAUt4RcLRvdiHQmNBDEFP9iTeSVCOlA=="], + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-33NpkQtmnsjLr9QdZvL3w8bjy+WoBJ+jY8JwuzxIq38rDNi1kwpBWW7Yjh+8bMlksd+ZAWW0fH4S/6OeoAdU5A=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/node-http-handler": "^4.4.14", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-stream": "^4.5.17", "tslib": "^2.6.2" } }, "sha512-9EJROO8LXll5a7eUFqu48k6BChrtokbmgeMWmsH7lBb6lVbtjslUYz/ShLi+SHkYzTomiGBhmzTW7y+H4BxsnA=="], + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.21", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.0", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-xFke7yjbON4unNOG0TApQwz+o1LH5VhVLgWlUuiLRWNDyBfeHIFje2ck8qHybvJ8Fkm5m3SsN+pvHtVo6PGWlQ=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/credential-provider-env": "^3.972.17", "@aws-sdk/credential-provider-http": "^3.972.19", "@aws-sdk/credential-provider-login": "^3.972.19", "@aws-sdk/credential-provider-process": "^3.972.17", "@aws-sdk/credential-provider-sso": "^3.972.19", "@aws-sdk/credential-provider-web-identity": "^3.972.19", "@aws-sdk/nested-clients": "^3.996.9", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-pVJVjWqVrPqjpFq7o0mCmeZu1Y0c94OCHSYgivdCD2wfmYVtBbwQErakruhgOD8pcMcx9SCqRw1pzHKR7OGBcA=="], + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.21", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/credential-provider-env": "^3.972.19", "@aws-sdk/credential-provider-http": "^3.972.21", "@aws-sdk/credential-provider-login": "^3.972.21", "@aws-sdk/credential-provider-process": "^3.972.19", "@aws-sdk/credential-provider-sso": "^3.972.21", "@aws-sdk/credential-provider-web-identity": "^3.972.21", "@aws-sdk/nested-clients": "^3.996.11", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-fmJN7KhB7CoG65w9fC2LVOd2wZbR2d1yJIpZNe2J5CeDPu7nUHSmavuJAeGEoE3OL5UIBVPNhmK/fV/NQrs3Hw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/nested-clients": "^3.996.9", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-jOXdZ1o+CywQKr6gyxgxuUmnGwTTnY2Kxs1PM7fI6AYtDWDnmW/yKXayNqkF8KjP1unflqMWKVbVt5VgmE3L0g=="], + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.21", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/nested-clients": "^3.996.11", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ENU+YCiuQocQjfIf9bPxZ+ZY0wIBkl3SMH22optBQwy8UFpSfonHynXzGT27xQxer4cYTNOpwDqbfo57BusbpQ=="], "@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.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-c8G8wT1axpJDgaP3xzcy+q8Y1fTi9A2eIQJvyhQ9xuXrUZhlCfXbC0vM9bM1CUXiZppFQ1p7g0tuUMvil/gCPg=="], + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-hjj5bFo4kf5/WzAMjDEFByVOMbq5gZiagIpJexf7Kp9nIDaGzhCphMsx03NCA8s9zUJzHlD1lXazd7MS+e03Lg=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/nested-clients": "^3.996.9", "@aws-sdk/token-providers": "3.1008.0", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-kVjQsEU3b///q7EZGrUzol9wzwJFKbEzqJKSq82A9ShrUTEO7FNylTtby3sPV19ndADZh1H3FB3+5ZrvKtEEeg=="], + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.21", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/nested-clients": "^3.996.11", "@aws-sdk/token-providers": "3.1012.0", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-9jWRCuMZpZKlqCZ46bvievqdfswsyB2yPAr9rOiN+FxaGgf8jrR5iYDqJgscvk1jrbAxiK4cIjHv3XjIAWAhzQ=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/nested-clients": "^3.996.9", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-BV1BlTFdG4w4tAihxN7iXDBoNcNewXD4q8uZlNQiUrnqxwGWUhKHODIQVSPlQGxXClEj+63m+cqZskw+ESmeZg=="], + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.21", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/nested-clients": "^3.996.11", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ShWQO/cQVZ+j3zUDK7Kj+m7grPzQCVA2iaZdJ+hJTGvVH5lR32Ip/rgZZ+zBdH6D6wczP9Upa4NMXoqJdGpK1g=="], "@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.993.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.993.0", "@aws-sdk/core": "^3.973.11", "@aws-sdk/credential-provider-cognito-identity": "^3.972.3", "@aws-sdk/credential-provider-env": "^3.972.9", "@aws-sdk/credential-provider-http": "^3.972.11", "@aws-sdk/credential-provider-ini": "^3.972.9", "@aws-sdk/credential-provider-login": "^3.972.9", "@aws-sdk/credential-provider-node": "^3.972.10", "@aws-sdk/credential-provider-process": "^3.972.9", "@aws-sdk/credential-provider-sso": "^3.972.9", "@aws-sdk/credential-provider-web-identity": "^3.972.9", "@aws-sdk/nested-clients": "3.993.0", "@aws-sdk/types": "^3.973.1", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.23.2", "@smithy/credential-provider-imds": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/property-provider": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-1M/nukgPSLqe9krzOKHnE8OylUaKAiokAV3xRLdeExVHcRE7WG5uzCTKWTj1imKvPjDqXq/FWhlbbdWIn7xIwA=="], @@ -740,7 +759,7 @@ "@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.1008.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/nested-clients": "^3.996.9", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-TulwlHQBWcJs668kNUDMZHN51DeLrDsYT59Ux4a/nbvr025gM6HjKJJ3LvnZccam7OS/ZKUVkWomCneRQKJbBg=="], + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1012.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/nested-clients": "^3.996.11", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-vzKwy020zjuiF4WTJzejx5nYcXJnRhHpb6i3lyZHIwfFwXG1yX4bzBVNMWYWF+bz1i2Pp2VhJbPyzpqj4VuJXQ=="], "@aws-sdk/types": ["@aws-sdk/types@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A=="], @@ -840,9 +859,9 @@ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], + "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], - "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], + "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], @@ -856,7 +875,7 @@ "@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.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], + "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], @@ -1228,25 +1247,27 @@ "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.2", "", { "dependencies": { "@hono/node-server": "^1.19.7", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww=="], + "@morphllm/morphsdk": ["@morphllm/morphsdk@0.2.141", "", { "dependencies": { "@vscode/ripgrep": "^1.17.0", "ai": ">=5.0.0", "diff": "^7.0.0", "isomorphic-git": "^1.25.10", "openai": "^4.52.7", "zod": ">=3.23.0" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.25.0", "@google/generative-ai": ">=0.21.0" }, "optionalPeers": ["@anthropic-ai/sdk", "@google/generative-ai"] }, "sha512-Vtqriw2gYpzp4A4IX0oQlLMI44aAe8zBKzWaOrmV7T6fi4T7IbKBzSBX7HjIFY1yEXILb8FpwdO6C6dkUlMhYQ=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - "@next/env": ["@next/env@16.1.6", "", {}, "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ=="], + "@next/env": ["@next/env@16.2.0", "", {}, "sha512-OZIbODWWAi0epQRCRjNe1VO45LOFBzgiyqmTLzIqWq6u1wrxKnAyz1HH6tgY/Mc81YzIjRPoYsPAEr4QV4l9TA=="], - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw=="], + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/JZsqKzKt01IFoiLLAzlNqys7qk2F3JkcUhj50zuRhKDQkZNOz9E5N6wAQWprXdsvjRP4lTFj+/+36NSv5AwhQ=="], - "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.1.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ=="], + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-/hV8erWq4SNlVgglUiW5UmQ5Hwy5EW/AbbXlJCn6zkfKxTy/E/U3V8U1Ocm2YCTUoFgQdoMxRyRMOW5jYy4ygg=="], - "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw=="], + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GkjL/Q7MWOwqWR9zoxu1TIHzkOI2l2BHCf7FzeQG87zPgs+6WDh+oC9Sw9ARuuL/FUk6JNCgKRkA6rEQYadUaw=="], - "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ=="], + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-1ffhC6KY5qWLg5miMlKJp3dZbXelEfjuXt1qcp5WzSCQy36CV3y+JT7OC1WSFKizGQCDOcQbfkH/IjZP3cdRNA=="], - "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ=="], + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-FmbDcZQ8yJRq93EJSL6xaE0KK/Rslraf8fj1uViGxg7K4CKBCRYSubILJPEhjSgZurpcPQq12QNOJQ0DRJl6Hg=="], - "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg=="], + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-HzjIHVkmGAwRbh/vzvoBWWEbb8BBZPxBvVbDQDvzHSf3D8RP/4vjw7MNLDXFF9Q1WEzeQyEj2zdxBtVAHu5Oyw=="], - "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.1.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw=="], + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-UMiFNQf5H7+1ZsZPxEsA064WEuFbRNq/kEXyepbCnSErp4f5iut75dBA8UeerFIG3vDaQNOfCpevnERPp2V+nA=="], - "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.1.6", "", { "os": "win32", "cpu": "x64" }, "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A=="], + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-DRrNJKW+/eimrZgdhVN1uvkN1OI4j6Lpefwr44jKQ0YQzztlmOBUUzHuV5GxOMPK3nmodAYElUVCY8ZXo/IWeA=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -1294,11 +1315,11 @@ "@opencode-ai/desktop-electron": ["@opencode-ai/desktop-electron@workspace:packages/desktop-electron"], - "@opencode-ai/plugin": ["@opencode-ai/plugin@1.2.25", "", { "dependencies": { "@opencode-ai/sdk": "1.2.25", "zod": "4.1.8" } }, "sha512-IQnjkcN7cvI/zoiDNx1d2qnGzn5BR/Bu95Kq05/vdd8oX4ARgYkqfaJgKkNSpjUVoNBKHTd8m9q1TtzuKlyGUg=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@1.2.27", "", { "dependencies": { "@opencode-ai/sdk": "1.2.27", "zod": "4.1.8" } }, "sha512-h+8Bw9v9nghMg7T+SUCTzxlIhOrsTqXW7U0HVLGQST5DjbN7uyCUM51roZWZ8LRjGxzbzFhvPnY1bj8i+ioZyw=="], "@opencode-ai/script": ["@opencode-ai/script@workspace:packages/script"], - "@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.25", "", {}, "sha512-ikuGWob48OM7LTgfXFqGOZKVOqh50FEjvtIBhXGhGowJhifmjZ+xuq/ypP8nPjTwUX73pbu1C3X9ZBWVkCN9mA=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.27", "", {}, "sha512-Wk0o/I+Fo+wE3zgvlJDs8Fb67KlKqX0PrV8dK5adSDkANq6r4Z25zXJg2iOir+a8ntg3rAcpel1OY4FV/TwRUA=="], "@opencode-ai/storybook": ["@opencode-ai/storybook@workspace:packages/storybook"], @@ -1340,21 +1361,21 @@ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="], - "@opentui/core": ["@opentui/core@0.1.86", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.86", "@opentui/core-darwin-x64": "0.1.86", "@opentui/core-linux-arm64": "0.1.86", "@opentui/core-linux-x64": "0.1.86", "@opentui/core-win32-arm64": "0.1.86", "@opentui/core-win32-x64": "0.1.86", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-3tRLbI9ADrQE1jEEn4x2aJexEOQZkv9Emk2BixMZqxfVhz2zr2SxtpimDAX0vmZK3+GnWAwBWxuaCAsxZpY4+w=="], + "@opentui/core": ["@opentui/core@0.1.87", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.87", "@opentui/core-darwin-x64": "0.1.87", "@opentui/core-linux-arm64": "0.1.87", "@opentui/core-linux-x64": "0.1.87", "@opentui/core-win32-arm64": "0.1.87", "@opentui/core-win32-x64": "0.1.87", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-dhsmMv0IqKftwG7J/pBrLBj2armsYIg5R3LBvciRQI/6X89GufP4l1u0+QTACAx6iR4SYJJNVNQ2tdX8LM9rMw=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.86", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Zp7q64+d+Dcx6YrH3mRcnHq8EOBnrfc1RvjgSWLhpXr49hY6LzuhqpfZM57aGErPYlR+ff8QM6e5FUkFnDfyjw=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.87", "", { "os": "darwin", "cpu": "arm64" }, "sha512-G8oq85diOfkU6n0T1CxCle7oDmpKxwhcdhZ9khBMU5IrfLx9ZDuCM3F6MsiRQWdvPPCq2oomNbd64bYkPamYgw=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.86", "", { "os": "darwin", "cpu": "x64" }, "sha512-NcxfjCJm1kLnTMVOpAPdRYNi8W8XdAXNa6N7i9khiVFrl2v5KRQfUjbrSOUYVxFJNc3jKFG6rsn3jEApvn92qA=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.87", "", { "os": "darwin", "cpu": "x64" }, "sha512-MYTFQfOHm6qO7YaY4GHK9u/oJlXY6djaaxl5I+k4p2mk3vvuFIl/AP1ypITwBFjyV5gyp7PRWFp4nGfY9oN8bw=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.86", "", { "os": "linux", "cpu": "arm64" }, "sha512-EDHAvqSOr8CXzbDvo1aE5blJ6wu1aSbR2LqoXtoeXHemr2T2W42D2TdIWewG6K+/BuRbzZnqt9wnYFBksLW6lw=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.87", "", { "os": "linux", "cpu": "arm64" }, "sha512-he8o1h5M6oskRJ7wE+xKJgmWnv5ZwN6gB3M/Z+SeHtOMPa5cZmi3TefTjG54llEgFfx0F9RcqHof7TJ/GNxRkw=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.86", "", { "os": "linux", "cpu": "x64" }, "sha512-VBaBkVdQDxYV4WcKjb+jgyMS5PiVHepvfaoKWpz1Bq+J01xXW4XPcXyPGkgR1+2R93KzaugEnLscTW4mWtLHlQ=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.87", "", { "os": "linux", "cpu": "x64" }, "sha512-aiUwjPlH4yDcB8/6YDKSmMkaoGAAltL0Xo0AzXyAtJXWK5tkCSaYjEVwzJ/rYRkr4Magnad+Mjth4AQUWdR2AA=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.86", "", { "os": "win32", "cpu": "arm64" }, "sha512-xKbT7sEKYKGwUPkoqmLfHjbJU+vwHPDwf/r/mIunL41JXQBB35CSZ3/QgIwpp2kkteu7oE1tdBdg15ogUU4OMg=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.87", "", { "os": "win32", "cpu": "arm64" }, "sha512-cmP0pOyREjWGniHqbDmaMY7U+1AyagrD8VseJbU0cGpNgVpG2/gbrJUGdfdLB0SNb+mzLdx6SOjdxtrElwRCQA=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.86", "", { "os": "win32", "cpu": "x64" }, "sha512-HRfgAUlcu71/MrtgfX4Gj7PsDtfXZiuC506Pkn1OnRN1Xomcu10BVRDweUa0/g8ldU9i9kLjMGGnpw6/NjaBFg=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.87", "", { "os": "win32", "cpu": "x64" }, "sha512-N2GErAAP8iODf2RPp86pilPaVKiD6G4pkpZL5nLGbKsl0bndrVTpSqZcn8+/nQwFZDPD/AsiRTYNOfWOblhzOw=="], - "@opentui/solid": ["@opentui/solid@0.1.86", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.86", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-pOZC9dlZIH+bpstVVZ2AvYukBnslZTKSl/y5H8FWcMTHGv/BzpGxXBxstL65E/IQASqPFbvFcs7yMRzdLhynmA=="], + "@opentui/solid": ["@opentui/solid@0.1.87", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.87", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-lRT9t30l8+FtgOjjWJcdb2MT6hP8/RKqwGgYwTI7fXrOqdhxxwdP2SM+rH2l3suHeASheiTdlvPAo230iUcsvg=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], @@ -1442,11 +1463,11 @@ "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - "@playwright/test": ["@playwright/test@1.58.2", "", { "dependencies": { "playwright": "1.58.2" }, "bin": { "playwright": "cli.js" } }, "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA=="], + "@playwright/test": ["@playwright/test@1.57.0", "", { "dependencies": { "playwright": "1.57.0" }, "bin": { "playwright": "cli.js" } }, "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA=="], - "@posthog/core": ["@posthog/core@1.23.3", "", { "dependencies": { "cross-spawn": "^7.0.6" } }, "sha512-nehG2nig9qiU4lEUIyfXQLaBnylm5wdDiIBsp2tBFJX5BcUHNAXSwpkHjKLQ9TDfik0HW1HwZ2mY/3hJgJNToQ=="], + "@posthog/core": ["@posthog/core@1.24.0", "", { "dependencies": { "cross-spawn": "^7.0.6" } }, "sha512-Wkp9mgNfgdf6+G4C1VMKakm2RXKQFf4bb5/CPQRAjpqv9l6BY36zZrD1+X5Y2XIAzZqbMKRxsDu3V1r6uKu7/A=="], - "@posthog/types": ["@posthog/types@1.360.1", "", {}, "sha512-zzvgckmzmjYB7YGnA2cIMtF9thj8O1TMp2YCXcBb+qnGcI5cKTo8j+lO7Kq1Lbwgp7ZPxBWUXfKHg03K5vVdjg=="], + "@posthog/types": ["@posthog/types@1.362.0", "", {}, "sha512-15wOI5uulkfzpkSQKVN4atZecAla2Hxr8IBIB8islqDvqY+42vbR+tMeDKMman9+FUoAqMzE0OnB8VIbM1QY0w=="], "@protobuf-ts/plugin": ["@protobuf-ts/plugin@2.11.1", "", { "dependencies": { "@bufbuild/protobuf": "^2.4.0", "@bufbuild/protoplugin": "^2.4.0", "@protobuf-ts/protoc": "^2.11.1", "@protobuf-ts/runtime": "^2.11.1", "@protobuf-ts/runtime-rpc": "^2.11.1", "typescript": "^3.9" }, "bin": { "protoc-gen-ts": "bin/protoc-gen-ts", "protoc-gen-dump": "bin/protoc-gen-dump" } }, "sha512-HyuprDcw0bEEJqkOWe1rnXUP0gwYLij8YhPuZyZk6cJbIgc/Q0IFgoHQxOXNIXAcXM4Sbehh6kjVnCzasElw1A=="], @@ -1578,7 +1599,7 @@ "@smithy/config-resolver": ["@smithy/config-resolver@4.4.11", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-YxFiiG4YDAtX7WMN7RuhHZLeTmRRAOyCbr+zB8e3AQzHPnUhS8zXjB1+cniPVQI3xbWsQPM0X2aaIkO/ME0ymw=="], - "@smithy/core": ["@smithy/core@3.23.11", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.19", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-952rGf7hBRnhUIaeLp6q4MptKW8sPFe5VvkoZ5qIzFAtx6c/QZ/54FS3yootsyUSf9gJX/NBqEBNdNR7jMIlpQ=="], + "@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg=="], @@ -1608,17 +1629,17 @@ "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA=="], - "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.25", "", { "dependencies": { "@smithy/core": "^3.23.11", "@smithy/middleware-serde": "^4.2.14", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-dqjLwZs2eBxIUG6Qtw8/YZ4DvzHGIf0DA18wrgtfP6a50UIO7e2nY0FPdcbv5tVJKqWCCU5BmGMOUwT7Puan+A=="], + "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.26", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-8Qfikvd2GVKSm8S6IbjfwFlRY9VlMrj0Dp4vTwAuhqbX7NhJKE5DQc2bnfJIcY0B+2YKMDBWfvexbSZeejDgeg=="], - "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.42", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.5", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-vbwyqHRIpIZutNXZpLAozakzamcINaRCpEy1MYmK6xBeW3xN+TyPRA123GjXnuxZIjc9848MRRCugVMTXxC4Eg=="], + "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.43", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-ZwsifBdyuNHrFGmbc7bAfP2b54+kt9J2rhFd18ilQGAB+GDiP4SrawqyExbB7v455QVR7Psyhb2kjULvBPIhvA=="], - "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.14", "", { "dependencies": { "@smithy/core": "^3.23.11", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-+CcaLoLa5apzSRtloOyG7lQvkUw2ZDml3hRh4QiG9WyEPfW5Ke/3tPOPiPjUneuT59Tpn8+c3RVaUvvkkwqZwg=="], + "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw=="], "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.12", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.16", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ULC8UCS/HivdCB3jhi+kLFYe4B5gxH2gi9vHBfEIiRrT2jfKiZNiETJSlzRtE6B26XbBHjPtc8iZKSNqMol9bw=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], "@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="], @@ -1634,7 +1655,7 @@ "@smithy/signature-v4": ["@smithy/signature-v4@5.3.12", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw=="], - "@smithy/smithy-client": ["@smithy/smithy-client@4.12.5", "", { "dependencies": { "@smithy/core": "^3.23.11", "@smithy/middleware-endpoint": "^4.4.25", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.19", "tslib": "^2.6.2" } }, "sha512-UqwYawyqSr/aog8mnLnfbPurS0gi4G7IYDcD28cUIBhsvWs1+rQcL2IwkUQ+QZ7dibaoRzhNF99fAQ9AUcO00w=="], + "@smithy/smithy-client": ["@smithy/smithy-client@4.12.6", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-aib3f0jiMsJ6+cvDnXipBsGDL7ztknYSVqJs1FdN9P+u9tr/VzOR7iygSh6EUOdaBeMCMSh3N0VdyYsG4o91DQ=="], "@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="], @@ -1650,9 +1671,9 @@ "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ=="], - "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.41", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.5", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-M1w1Ux0rSVvBOxIIiqbxvZvhnjQ+VUjJrugtORE90BbadSTH+jsQL279KRL3Hv0w69rE7EuYkV/4Lepz/NBW9g=="], + "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.42", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-0vjwmcvkWAUtikXnWIUOyV6IFHTEeQUYh3JUZcDgcszF+hD/StAsQ3rCZNZEPHgI9kVNcbnyc8P2CBHnwgmcwg=="], - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.44", "", { "dependencies": { "@smithy/config-resolver": "^4.4.11", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.5", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-YPze3/lD1KmWuZsl9JlfhcgGLX7AXhSoaCDtiPntUjNW5/YY0lOHjkcgxyE9x/h5vvS1fzDifMGjzqnNlNiqOQ=="], + "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.45", "", { "dependencies": { "@smithy/config-resolver": "^4.4.11", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-q5dOqqfTgUcLe38TAGiFn9srToKj2YCHJ34QGOLzM+xYLLA+qRZv7N+33kl1MERVusue36ZHnlNaNEvY/PzSrw=="], "@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig=="], @@ -1662,7 +1683,7 @@ "@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], - "@smithy/util-stream": ["@smithy/util-stream@4.5.19", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.4.16", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-v4sa+3xTweL1CLO2UP0p7tvIMH/Rq1X4KKOxd568mpe6LSLMQCnDHs4uv7m3ukpl3HvcN2JH6jiCS0SNRXKP/w=="], + "@smithy/util-stream": ["@smithy/util-stream@4.5.20", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.0", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw=="], "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw=="], @@ -1688,6 +1709,8 @@ "@solid-primitives/keyed": ["@solid-primitives/keyed@1.5.3", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zNadtyYBhJSOjXtogkGHmRxjGdz9KHc8sGGVAGlUABkE8BED2tbIZoxkwSqzOwde8OcUEH0bb5DLZUWIMvyBSA=="], + "@solid-primitives/lifecycle": ["@solid-primitives/lifecycle@0.1.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-+K0T10kZXqorocFj0coIqt8NYm2UqoZfpF3nm2RwrDMZMV+C+SC0Oi3N6Dnq2i7W/n1cHAnfpoV4CBLsW21lJw=="], + "@solid-primitives/map": ["@solid-primitives/map@0.4.13", "", { "dependencies": { "@solid-primitives/trigger": "^1.1.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew=="], "@solid-primitives/media": ["@solid-primitives/media@2.3.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-hQ4hLOGvfbugQi5Eu1BFWAIJGIAzztq9x0h02xgBGl2l0Jaa3h7tg6bz5tV1NSuNYVGio4rPoa7zVQQLkkx9dA=="], @@ -1698,7 +1721,7 @@ "@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.5", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.5", "@solid-primitives/rootless": "^1.5.3", "@solid-primitives/static-store": "^0.1.3", "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AiyTknKcNBaKHbcSMuxtSNM8FjIuiSuFyFghdD0TcCMU9hKi9EmsC5pjfjDwxE+5EueB1a+T/34PLRI5vbBbKw=="], - "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], + "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="], "@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="], @@ -1728,15 +1751,15 @@ "@storybook/addon-docs": ["@storybook/addon-docs@10.2.10", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.2.10", "@storybook/icons": "^2.0.1", "@storybook/react-dom-shim": "10.2.10", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.2.10" } }, "sha512-2wIYtdvZIzPbQ5194M5Igpy8faNbQ135nuO5ZaZ2VuttqGr+IJcGnDP42zYwbAsGs28G8ohpkbSgIzVyJWUhPQ=="], - "@storybook/addon-links": ["@storybook/addon-links@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.2.18" }, "optionalPeers": ["react"] }, "sha512-sMZB7S/PyEWoguVdeKem5BrFNhdosfdbCEhVRVnLG9/CBt1PBhkYryEvcDPIVqQOVDCn6+myQ1j7es3RN6P1Uw=="], + "@storybook/addon-links": ["@storybook/addon-links@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.3.0" }, "optionalPeers": ["react"] }, "sha512-F0/UPO3HysoJoAFrBSqWkRP3lK2owHSAgQNEFB9mNihsAQbHHg9xer22VROL012saprs98+V/hNUZs4zPy9zlg=="], - "@storybook/addon-onboarding": ["@storybook/addon-onboarding@10.2.18", "", { "peerDependencies": { "storybook": "^10.2.18" } }, "sha512-RpY1MErrfncvK+zArp3hEitisEBRsWDoLe/Z1BWvk+E2G31osyurzxj0UaYr+rjuzQiOQX3k63yVVlyXq6DIzg=="], + "@storybook/addon-onboarding": ["@storybook/addon-onboarding@10.3.0", "", { "peerDependencies": { "storybook": "^10.3.0" } }, "sha512-zhSmxO1VDntnAxSCvw1R9h2+KvAnY0PeDdhyrr9hQdVL1j3SEXxegc3dm/YJRhtBk6S2KPLgPU5+UQuFF0p2nA=="], "@storybook/addon-themes": ["@storybook/addon-themes@10.2.10", "", { "dependencies": { "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.2.10" } }, "sha512-j7ixCgzpWeTU7K4BkNHtEg3NdmRg9YW7ynvv0OjD3vaz4+FUVWOq7PPwb3SktLS1tOl4UA13IpApD8nSpBiY6A=="], - "@storybook/addon-vitest": ["@storybook/addon-vitest@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1" }, "peerDependencies": { "@vitest/browser": "^3.0.0 || ^4.0.0", "@vitest/browser-playwright": "^4.0.0", "@vitest/runner": "^3.0.0 || ^4.0.0", "storybook": "^10.2.18", "vitest": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@vitest/browser", "@vitest/browser-playwright", "@vitest/runner", "vitest"] }, "sha512-jiyR1A45cdTEg14dL2IrdCxxO+j9pboUxeuAuOaGeI0p3pP8fSRblfbvf+tf+dv0NJi8Lipd+PIMTjNDg36nKw=="], + "@storybook/addon-vitest": ["@storybook/addon-vitest@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1" }, "peerDependencies": { "@vitest/browser": "^3.0.0 || ^4.0.0", "@vitest/browser-playwright": "^4.0.0", "@vitest/runner": "^3.0.0 || ^4.0.0", "storybook": "^10.3.0", "vitest": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@vitest/browser", "@vitest/browser-playwright", "@vitest/runner", "vitest"] }, "sha512-DOLlnWhQ0IhTGaBJfymSVkSt6ECZLskdvZK/CtgThpubGuOoTToUsso9RNhzIZjYxKT2QwvGRPJENQmv5XOqeg=="], - "@storybook/builder-vite": ["@storybook/builder-vite@10.2.18", "", { "dependencies": { "@storybook/csf-plugin": "10.2.18", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.2.18", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-HOCH15oMNjWft0Mqf7Q/wVBg/zeP+FDznhpGEFo2g9r0NaqJsjeiBpJvYo3ox0szyd4i8TtS+63zxJ9mxjpksw=="], + "@storybook/builder-vite": ["@storybook/builder-vite@10.3.0", "", { "dependencies": { "@storybook/csf-plugin": "10.3.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.3.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-T7LfZPE31j94Jkk66bnsxMibBnbLYmebLIDgPSYzeN3ZkjPfoFhhi2+8Zxneth5cQCGRkCAhRTV0tYmFp1+H6g=="], "@storybook/csf-plugin": ["@storybook/csf-plugin@10.2.10", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.2.10", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-aFvgaNDAnKMjuyhPK5ialT22pPqMN0XfPBNPeeNVPYztngkdKBa8WFqF/umDd47HxAjebq+vn6uId1xHyOHH3g=="], @@ -1750,35 +1773,35 @@ "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], - "@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="], + "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.2", "", { "os": "android", "cpu": "arm64" }, "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2", "", { "os": "linux", "cpu": "arm" }, "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.2", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA=="], - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.1", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "postcss": "^8.5.6", "tailwindcss": "4.2.1" } }, "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.2", "@tailwindcss/oxide": "4.2.2", "postcss": "^8.5.6", "tailwindcss": "4.2.2" } }, "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ=="], "@tailwindcss/vite": ["@tailwindcss/vite@4.1.11", "", { "dependencies": { "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "tailwindcss": "4.1.11" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw=="], @@ -2022,6 +2045,8 @@ "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], + "@types/which": ["@types/which@3.0.4", "", {}, "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], @@ -2030,41 +2055,41 @@ "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/type-utils": "8.57.0", "@typescript-eslint/utils": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.1", "@typescript-eslint/type-utils": "8.57.1", "@typescript-eslint/utils": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.1", "@typescript-eslint/types": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.1", "@typescript-eslint/types": "^8.57.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0" } }, "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.1", "", { "dependencies": { "@typescript-eslint/types": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1" } }, "sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.1", "", { "dependencies": { "@typescript-eslint/types": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1", "@typescript-eslint/utils": "8.57.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.57.1", "", {}, "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.1", "@typescript-eslint/tsconfig-utils": "8.57.1", "@typescript-eslint/types": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.1", "@typescript-eslint/types": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.1", "", { "dependencies": { "@typescript-eslint/types": "8.57.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A=="], - "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20251207.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20251207.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-4QcRnzB0pi9rS0AOvg8kWbmuwHv5X7B2EXHbgcms9+56hsZ8SZrZjNgBJb2rUIodJ4kU5mrkj/xlTTT4r9VcpQ=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260316.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260316.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260316.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260316.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260316.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260316.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260316.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260316.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-s+QGNx+3zxTZBuZw3oNOFlHqpbmg0cTgBd/b6SRZ5mo3vFChkhflYqRW2IvTvU9a3PPX3bQAkQ/gWbDZCmNC3Q=="], - "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-waWJnuuvkXh4WdpbTjYf7pyahJzx0ycesV2BylyHrE9OxU9FSKcD/cRLQYvbq3YcBSdF7sZwRLDBer7qTeLsYA=="], + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260316.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TjeMEMabLsc5VNYy8WVlu1oHBVqibwSbkIRSyqANFxyD6iWnCFquDvliwErVo8TFIu0c8C+C+tgFSvYkhVZMMw=="], - "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-3bkD9QuIjxETtp6J1l5X2oKgudJ8z+8fwUq0izCjK1JrIs2vW1aQnbzxhynErSyHWH7URGhHHzcsXHbikckAsg=="], + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260316.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Lv/JmtMfNbMJiIEZlByQ5zSR1t9WoE8rFuZxU0vpiyfUEjSbuBMG8pt+Ryqj6uiylR3XThlV3EaVYsJ7Um6n8w=="], - "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OjrZBq8XJkB7uCQvT1AZ1FPsp+lT0cHxY5SisE+ZTAU6V0IHAZMwJ7J/mnwlGsBcCKRLBT+lX3hgEuOTSwHr9w=="], + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260316.1", "", { "os": "linux", "cpu": "arm" }, "sha512-vItkqjOuVY9OfqdovSyEjnAbNMM+QGM9AqzGRknX1nZjGlWXsUTL3IPuv5by69SOqw5TLi8ddx82cyu6F3ZRVQ=="], - "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qhp06OObkwy5B+PlAhAmq+Ls3GVt4LHAovrTRcpLB3Mk3yJ0h9DnIQwPQiayp16TdvTsGHI3jdIX4MGm5L/ghA=="], + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260316.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-xA4DekkAesjnWyp8p0iF79Rf0q2NVszxedd9M2Ztb0WBSDQFiECVYJSQMFd4+FKNiSq9DnadPy68Dly+B1r17A=="], - "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "x64" }, "sha512-fPRw0zfTBeVmrkgi5Le+sSwoeAz6pIdvcsa1OYZcrspueS9hn3qSC5bLEc5yX4NJP1vItadBqyGLUQ7u8FJjow=="], + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260316.1", "", { "os": "linux", "cpu": "x64" }, "sha512-osY+4HCIpi9Bu4jNz49k8BVOB9A04BG6mWF7WltmAQWBIAeosa4n/qtKokfAZDTD5/moHSn20p7hZAlGI8JWjw=="], - "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20251207.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-KxY1i+HxeSFfzZ+HVsKwMGBM79laTRZv1ibFqHu22CEsfSPDt4yiV1QFis8Nw7OBXswNqJG/UGqY47VP8FeTvw=="], + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260316.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-DcWceiTXClIakJhk0+8KjQ+pBp435HaA6uw9EtDTo75uWUEPVf9D489KKbylRChci/paYX8uPKlROo9+6N8M9g=="], - "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20251207.1", "", { "os": "win32", "cpu": "x64" }, "sha512-5l51HlXjX7lXwo65DEl1IaCFLjmkMtL6K3NrSEamPNeNTtTQwZRa3pQ9V65dCglnnCQ0M3+VF1RqzC7FU0iDKg=="], + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260316.1", "", { "os": "win32", "cpu": "x64" }, "sha512-LvpV1hyQS0U9yMLHgWexhC7oSeBpcNbIJtYC6Iyvu63Mb6J/cP0k2fQmnAVB2yesMMQFtuY6v2YIx17vE0Ymfw=="], "@typescript/vfs": ["@typescript/vfs@1.6.4", "", { "dependencies": { "debug": "^4.4.3" }, "peerDependencies": { "typescript": "*" } }, "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ=="], @@ -2090,6 +2115,8 @@ "@vscode/codicons": ["@vscode/codicons@0.0.44", "", {}, "sha512-F7qPRumUK3EHjNdopfICLGRf3iNPoZQt+McTHAn4AlOWPB3W2kL4H0S7uqEqbyZ6rCxaeDjpAn3MCUnwTu/VJQ=="], + "@vscode/ripgrep": ["@vscode/ripgrep@1.17.1", "", { "dependencies": { "https-proxy-agent": "^7.0.2", "proxy-from-env": "^1.1.0", "yauzl": "^2.9.2" } }, "sha512-xTs7DGyAO3IsJYOCTBP8LnTvPiYVKEuyv8s0xyJDBXfs8rhBfqnZPvb6xDT+RnwWzcXqW27xLS/aGrkjX7lNWw=="], + "@vscode/test-cli": ["@vscode/test-cli@0.0.12", "", { "dependencies": { "@types/mocha": "^10.0.10", "c8": "^10.1.3", "chokidar": "^3.6.0", "enhanced-resolve": "^5.18.3", "glob": "^10.3.10", "minimatch": "^9.0.3", "mocha": "^11.7.4", "supports-color": "^10.2.2", "yargs": "^17.7.2" }, "bin": { "vscode-test": "out/bin.mjs" } }, "sha512-iYN0fDg29+a2Xelle/Y56Xvv7Nc8Thzq4VwpzAF/SIE6918rDicqfsQxV6w1ttr2+SOm+10laGuY9FG2ptEKsQ=="], "@vscode/test-electron": ["@vscode/test-electron@2.5.2", "", { "dependencies": { "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.5", "jszip": "^3.10.1", "ora": "^8.1.0", "semver": "^7.6.2" } }, "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg=="], @@ -2134,10 +2161,14 @@ "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + "acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + "aggregate-error": ["aggregate-error@4.0.1", "", { "dependencies": { "clean-stack": "^4.0.0", "indent-string": "^5.0.0" } }, "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w=="], + "ai": ["ai@5.0.124", "", { "dependencies": { "@ai-sdk/gateway": "2.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Li6Jw9F9qsvFJXZPBfxj38ddP2iURCnMs96f9Q3OeQzrDVcl1hvtwSEAuxA/qmfh6SDV2ERqFUOFzigvr0697g=="], "ai-gateway-provider": ["ai-gateway-provider@2.3.1", "", { "dependencies": { "@ai-sdk/provider": "^2.0.0", "@ai-sdk/provider-utils": "^3.0.19", "ai": "^5.0.116" }, "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^3.0.71", "@ai-sdk/anthropic": "^2.0.56", "@ai-sdk/azure": "^2.0.90", "@ai-sdk/cerebras": "^1.0.33", "@ai-sdk/cohere": "^2.0.21", "@ai-sdk/deepgram": "^1.0.21", "@ai-sdk/deepseek": "^1.0.32", "@ai-sdk/elevenlabs": "^1.0.21", "@ai-sdk/fireworks": "^1.0.30", "@ai-sdk/google": "^2.0.51", "@ai-sdk/google-vertex": "3.0.90", "@ai-sdk/groq": "^2.0.33", "@ai-sdk/mistral": "^2.0.26", "@ai-sdk/openai": "^2.0.88", "@ai-sdk/perplexity": "^2.0.22", "@ai-sdk/xai": "^2.0.42", "@openrouter/ai-sdk-provider": "^1.5.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^1.0.29" } }, "sha512-PqI6TVNEDNwr7kOhy7XUGnA8XJB1SpeA9aLqGjr0CyWkKgH+y+ofPm8MZGZ74DOwVejDF+POZq0Qs9jKEKUeYg=="], @@ -2174,6 +2205,14 @@ "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + "array-find-index": ["array-find-index@1.0.2", "", {}, "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw=="], + + "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], + + "arrgv": ["arrgv@1.0.2", "", {}, "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw=="], + + "arrify": ["arrify@3.0.0", "", {}, "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw=="], + "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], @@ -2186,6 +2225,8 @@ "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], + "async-lock": ["async-lock@1.4.1", "", {}, "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="], + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="], @@ -2196,6 +2237,8 @@ "autoprefixer": ["autoprefixer@10.4.27", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA=="], + "ava": ["ava@5.3.1", "", { "dependencies": { "acorn": "^8.8.2", "acorn-walk": "^8.2.0", "ansi-styles": "^6.2.1", "arrgv": "^1.0.2", "arrify": "^3.0.0", "callsites": "^4.0.0", "cbor": "^8.1.0", "chalk": "^5.2.0", "chokidar": "^3.5.3", "chunkd": "^2.0.1", "ci-info": "^3.8.0", "ci-parallel-vars": "^1.0.1", "clean-yaml-object": "^0.1.0", "cli-truncate": "^3.1.0", "code-excerpt": "^4.0.0", "common-path-prefix": "^3.0.0", "concordance": "^5.0.4", "currently-unhandled": "^0.4.1", "debug": "^4.3.4", "emittery": "^1.0.1", "figures": "^5.0.0", "globby": "^13.1.4", "ignore-by-default": "^2.1.0", "indent-string": "^5.0.0", "is-error": "^2.2.2", "is-plain-object": "^5.0.0", "is-promise": "^4.0.0", "matcher": "^5.0.0", "mem": "^9.0.2", "ms": "^2.1.3", "p-event": "^5.0.1", "p-map": "^5.5.0", "picomatch": "^2.3.1", "pkg-conf": "^4.0.0", "plur": "^5.1.0", "pretty-ms": "^8.0.0", "resolve-cwd": "^3.0.0", "stack-utils": "^2.0.6", "strip-ansi": "^7.0.1", "supertap": "^3.0.1", "temp-dir": "^3.0.0", "write-file-atomic": "^5.0.1", "yargs": "^17.7.2" }, "peerDependencies": { "@ava/typescript": "*" }, "optionalPeers": ["@ava/typescript"], "bin": { "ava": "entrypoints/cli.mjs" } }, "sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg=="], + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "avvio": ["avvio@9.2.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ=="], @@ -2236,7 +2279,7 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.7", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-1ghYO3HnxGec0TCGBXiDLVns4eCSx4zJpxnHrlqFQajmhfKMQBzUGDdkMK7fUW7PTHTeLf+j87aTuKuuwWzMGw=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.8", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ=="], "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], @@ -2250,6 +2293,8 @@ "bl": ["bl@6.1.6", "", { "dependencies": { "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^4.2.0" } }, "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg=="], + "blueimp-md5": ["blueimp-md5@2.19.0", "", {}, "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="], + "bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="], "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], @@ -2326,11 +2371,13 @@ "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + "callsites": ["callsites@4.2.0", "", {}, "sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ=="], "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001778", "", {}, "sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg=="], + "caniuse-lite": ["caniuse-lite@1.0.30001780", "", {}, "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ=="], + + "cbor": ["cbor@8.1.0", "", { "dependencies": { "nofilter": "^3.1.0" } }, "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -2360,15 +2407,25 @@ "chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="], + "chunkd": ["chunkd@2.0.1", "", {}, "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ=="], + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "ci-parallel-vars": ["ci-parallel-vars@1.0.1", "", {}, "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg=="], + "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "clean-git-ref": ["clean-git-ref@2.0.1", "", {}, "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw=="], + + "clean-stack": ["clean-stack@4.2.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg=="], + + "clean-yaml-object": ["clean-yaml-object@0.1.0", "", {}, "sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw=="], + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="], - "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], + "cli-truncate": ["cli-truncate@3.1.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^5.0.0" } }, "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA=="], "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], @@ -2384,6 +2441,8 @@ "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], + "code-excerpt": ["code-excerpt@4.0.0", "", { "dependencies": { "convert-to-spaces": "^2.0.1" } }, "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -2396,12 +2455,16 @@ "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], + "common-path-prefix": ["common-path-prefix@3.0.0", "", {}, "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w=="], + "compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="], "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=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "concordance": ["concordance@5.0.4", "", { "dependencies": { "date-time": "^3.1.0", "esutils": "^2.0.3", "fast-diff": "^1.2.0", "js-string-escape": "^1.0.1", "lodash": "^4.17.15", "md5-hex": "^3.0.1", "semver": "^7.3.2", "well-known-symbols": "^2.0.0" } }, "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw=="], + "conf": ["conf@14.0.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "atomically": "^2.0.3", "debounce-fn": "^6.0.0", "dot-prop": "^9.0.0", "env-paths": "^3.0.0", "json-schema-typed": "^8.0.1", "semver": "^7.7.2", "uint8array-extras": "^1.4.0" } }, "sha512-L6BuueHTRuJHQvQVc6YXYZRtN5vJUtOdCTLn0tRYYV5azfbAFcPghB5zEE40mVrV6w7slMTqUfkDomutIK14fw=="], "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], @@ -2414,11 +2477,13 @@ "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "convert-to-spaces": ["convert-to-spaces@2.0.1", "", {}, "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ=="], + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], - "core-js": ["core-js@3.48.0", "", {}, "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ=="], + "core-js": ["core-js@3.49.0", "", {}, "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg=="], "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], @@ -2446,6 +2511,8 @@ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "currently-unhandled": ["currently-unhandled@0.4.1", "", { "dependencies": { "array-find-index": "^1.0.1" } }, "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng=="], + "cytoscape": ["cytoscape@3.33.1", "", {}, "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ=="], "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="], @@ -2520,6 +2587,8 @@ "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], + "date-time": ["date-time@3.1.0", "", { "dependencies": { "time-zone": "^1.0.0" } }, "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg=="], + "dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="], "debounce-fn": ["debounce-fn@6.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ=="], @@ -2566,6 +2635,8 @@ "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], @@ -2574,10 +2645,14 @@ "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + "diff3": ["diff3@0.0.3", "", {}, "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g=="], + "dijkstrajs": ["dijkstrajs@1.0.3", "", {}, "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="], "dir-compare": ["dir-compare@4.2.0", "", { "dependencies": { "minimatch": "^3.0.5", "p-limit": "^3.1.0 " } }, "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ=="], + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + "dmg-builder": ["dmg-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg=="], "dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "^3.0.1", "@types/verror": "^1.10.3", "ajv": "^6.10.0", "crc": "^3.8.0", "iconv-corefoundation": "^1.1.7", "plist": "^3.0.4", "smart-buffer": "^4.0.2", "verror": "^1.10.0" }, "os": "darwin", "bin": { "dmg-license": "bin/dmg-license.js" } }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="], @@ -2602,9 +2677,9 @@ "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], - "drizzle-kit": ["drizzle-kit@1.0.0-beta.12-a5629fb", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "tsx": "^4.20.6" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-l+p4QOMvPGYBYEE9NBlU7diu+NSlxuOUwi0I7i01Uj1PpfU0NxhPzaks/9q1MDw4FAPP8vdD0dOhoqosKtRWWQ=="], + "drizzle-kit": ["drizzle-kit@1.0.0-beta.16-ea816b6", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-GiJQqCNPZP8Kk+i7/sFa3rtXbq26tLDNi3LbMx9aoLuwF2ofk8CS7cySUGdI+r4J3q0a568quC8FZeaFTCw4IA=="], - "drizzle-orm": ["drizzle-orm@1.0.0-beta.12-a5629fb", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-wyOAgr9Cy9oEN6z5S0JGhfipLKbRRJtQKgbDO9SXGR9swMBbGNIlXkeMqPRrqYQ8k70mh+7ZJ/eVmJ2F7zR3Vg=="], + "drizzle-orm": ["drizzle-orm@1.0.0-beta.16-ea816b6", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-k9gT4f0O9Qvah5YK/zL+FZonQ8TPyVxcG/ojN4dzO0fHP8hs8tBno8lqmJo53g0JLWv3Q2nsTUoyBRKM2TljFw=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -2630,7 +2705,7 @@ "electron-store": ["electron-store@10.1.0", "", { "dependencies": { "conf": "^14.0.0", "type-fest": "^4.41.0" } }, "sha512-oL8bRy7pVCLpwhmXy05Rh/L6O93+k9t6dqSw0+MckIc3OmCTZm6Mp04Q4f/J0rtu84Ky6ywkR8ivtGOmrq+16w=="], - "electron-to-chromium": ["electron-to-chromium@1.5.313", "", {}, "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA=="], + "electron-to-chromium": ["electron-to-chromium@1.5.321", "", {}, "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ=="], "electron-updater": ["electron-updater@6.8.3", "", { "dependencies": { "builder-util-runtime": "9.5.1", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", "semver": "~7.7.3", "tiny-typed-emitter": "^2.1.0" } }, "sha512-Z6sgw3jgbikWKXei1ENdqFOxBP0WlXg3TtKfz0rgw2vIZFJUyI4pD7ZN7jrkm7EoMK+tcm/qTnPUdqfZukBlBQ=="], @@ -2640,6 +2715,8 @@ "electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", "lodash": "^4.17.21", "temp": "^0.9.0" }, "optionalDependencies": { "@electron/windows-sign": "^1.1.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="], + "emittery": ["emittery@1.2.1", "", {}, "sha512-sFz64DCRjirhwHLxofFqxYQm6DCp6o0Ix7jwKQvuCHPn4GMRZNuBZyLPu9Ccmk/QSCAMZt6FOUqA8JZCQvA9fw=="], + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], @@ -2654,7 +2731,7 @@ "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], - "enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="], + "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], @@ -2750,6 +2827,8 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], + "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], @@ -2764,9 +2843,9 @@ "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], - "fast-xml-builder": ["fast-xml-builder@1.1.3", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-1o60KoFw2+LWKQu3IdcfcFlGTW4dpqEWmjhYec6H82AYZU2TVBXep6tMl8Z1Y+wM+ZrzCwe3BZ9Vyd9N2rIvmg=="], + "fast-xml-builder": ["fast-xml-builder@1.1.4", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg=="], - "fast-xml-parser": ["fast-xml-parser@5.5.5", "", { "dependencies": { "fast-xml-builder": "^1.1.3", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-NLY+V5NNbdmiEszx9n14mZBseJTC50bRq1VHsaxOmR72JDuZt+5J1Co+dC/4JPnyq+WrIHNM69r0sqf7BMb3Mg=="], + "fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", {}, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="], @@ -2786,6 +2865,8 @@ "fflate": ["fflate@0.4.8", "", {}, "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="], + "figures": ["figures@5.0.0", "", { "dependencies": { "escape-string-regexp": "^5.0.0", "is-unicode-supported": "^1.2.0" } }, "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg=="], + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], "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=="], @@ -2806,7 +2887,7 @@ "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - "flatted": ["flatted@3.4.1", "", {}, "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ=="], + "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="], "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], @@ -2828,10 +2909,12 @@ "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], - "framer-motion": ["framer-motion@12.36.0", "", { "dependencies": { "motion-dom": "^12.36.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-4PqYHAT7gev0ke0wos+PyrcFxI0HScjm3asgU8nSYa8YzJFuwgIvdj3/s3ZaxLq0bUSboIn19A2WS/MHwLCvfw=="], + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + "friendly-words": ["friendly-words@1.3.1", "", { "dependencies": { "ava": "^5.3.1", "express": "^4.18.2", "lodash.samplesize": "^4.2.0" } }, "sha512-gLlK15jM/U/oFtYkw4At0cVS0kWst41BRPG4EnhP/L7ZGn8rnOSlLuffIvO/JIK06TYx7abRpNMTzkwpHL+kEA=="], + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], "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=="], @@ -2864,9 +2947,7 @@ "get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], - "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], - - "ghostty-web": ["ghostty-web@0.4.0", "", {}, "sha512-0puDBik2qapbD/QQBW9o5ZHfXnZBqZWx/ctBiVtKZ6ZLds4NYb+wZuw1cRLXZk9zYovIQ908z3rvFhexAvc5Hg=="], + "ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#4af877d", {}, "anomalyco-ghostty-web-4af877d", "sha512-fbEK8mtr7ar4ySsF+JUGjhaZrane7dKphanN+SxHt5XXI6yLMAh/Hpf6sNCOyyVa2UlGCd7YpXG/T2v2RUAX+A=="], "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], @@ -2962,6 +3043,8 @@ "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + "ignore-by-default": ["ignore-by-default@2.1.0", "", {}, "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw=="], + "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="], "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], @@ -2970,7 +3053,7 @@ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + "indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], "index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="], @@ -2980,12 +3063,14 @@ "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + "internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], + "irregular-plurals": ["irregular-plurals@3.5.0", "", {}, "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ=="], + "is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="], "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], @@ -2996,6 +3081,8 @@ "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + "is-error": ["is-error@2.2.2", "", {}, "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg=="], + "is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -3018,6 +3105,8 @@ "is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="], + "is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], "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=="], @@ -3038,7 +3127,9 @@ "isbinaryfile": ["isbinaryfile@5.0.7", "", {}, "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "isomorphic-git": ["isomorphic-git@1.37.4", "", { "dependencies": { "async-lock": "^1.4.1", "clean-git-ref": "^2.0.1", "crc-32": "^1.2.0", "diff3": "0.0.3", "ignore": "^5.1.4", "minimisted": "^2.0.0", "pako": "^1.0.10", "pify": "^4.0.1", "readable-stream": "^4.0.0", "sha.js": "^2.4.12", "simple-get": "^4.0.1" }, "bin": { "isogit": "cli.cjs" } }, "sha512-fNnCEJtI1refeVxysiuqGP9cubUoLibUS6UIDUWSy5Op6sVdFwGv/SpzfhMFiDkfgYoXKqurZ+LVxEeesy+T0Q=="], "isomorphic-ws": ["isomorphic-ws@5.0.0", "", { "peerDependencies": { "ws": "*" } }, "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw=="], @@ -3066,6 +3157,8 @@ "js-md4": ["js-md4@0.3.2", "", {}, "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA=="], + "js-string-escape": ["js-string-escape@1.0.1", "", {}, "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg=="], + "js-tiktoken": ["js-tiktoken@1.0.21", "", { "dependencies": { "base64-js": "^1.5.1" } }, "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], @@ -3142,32 +3235,34 @@ "light-my-request": ["light-my-request@6.6.0", "", { "dependencies": { "cookie": "^1.0.1", "process-warning": "^4.0.0", "set-cookie-parser": "^2.6.0" } }, "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A=="], - "lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="], + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="], + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="], + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="], + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="], + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="], + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], + "load-json-file": ["load-json-file@7.0.1", "", {}, "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ=="], + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], @@ -3194,6 +3289,8 @@ "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "lodash.samplesize": ["lodash.samplesize@4.2.0", "", {}, "sha512-1ZhKV7/nuISuaQdxfCqrs4HHxXIYN+0Z4f7NMQn2PHkxFZJGavJQ1j/paxyJnLJmN2ZamNN6SMepneV+dCgQTA=="], + "lodash.truncate": ["lodash.truncate@4.4.2", "", {}, "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="], "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], @@ -3206,7 +3303,7 @@ "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="], - "lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], + "lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="], "lru_map": ["lru_map@0.4.1", "", {}, "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg=="], @@ -3222,6 +3319,8 @@ "make-fetch-happen": ["make-fetch-happen@14.0.3", "", { "dependencies": { "@npmcli/agent": "^3.0.0", "cacache": "^19.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "ssri": "^12.0.0" } }, "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ=="], + "map-age-cleaner": ["map-age-cleaner@0.1.3", "", { "dependencies": { "p-defer": "^1.0.0" } }, "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w=="], + "markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], "marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="], @@ -3230,16 +3329,20 @@ "marked-shiki": ["marked-shiki@1.2.1", "", { "peerDependencies": { "marked": ">=7.0.0", "shiki": ">=1.0.0" } }, "sha512-yHxYQhPY5oYaIRnROn98foKhuClark7M373/VpLxiy5TrDu9Jd/LsMwo8w+U91Up4oDb9IXFrP0N1MFRz8W/DQ=="], - "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + "matcher": ["matcher@5.0.0", "", { "dependencies": { "escape-string-regexp": "^5.0.0" } }, "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "md5-hex": ["md5-hex@3.0.1", "", { "dependencies": { "blueimp-md5": "^2.10.0" } }, "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw=="], + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + "mem": ["mem@9.0.2", "", { "dependencies": { "map-age-cleaner": "^0.1.3", "mimic-fn": "^4.0.0" } }, "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A=="], + "merge-anything": ["merge-anything@5.1.7", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ=="], "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], @@ -3250,6 +3353,8 @@ "mermaid": ["mermaid@11.12.3", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.1", "@mermaid-js/parser": "^1.0.0", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.13", "dayjs": "^1.11.18", "dompurify": "^3.2.5", "katex": "^0.16.22", "khroma": "^2.1.0", "lodash-es": "^4.17.23", "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0" } }, "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ=="], + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], @@ -3280,6 +3385,8 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "minimisted": ["minimisted@2.0.1", "", { "dependencies": { "minimist": "^1.2.5" } }, "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], @@ -3330,9 +3437,9 @@ "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "next": ["next@16.1.6", "", { "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-x64": "16.1.6", "@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-musl": "16.1.6", "@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw=="], + "next": ["next@16.2.0", "", { "dependencies": { "@next/env": "16.2.0", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.0", "@next/swc-darwin-x64": "16.2.0", "@next/swc-linux-arm64-gnu": "16.2.0", "@next/swc-linux-arm64-musl": "16.2.0", "@next/swc-linux-x64-gnu": "16.2.0", "@next/swc-linux-x64-musl": "16.2.0", "@next/swc-win32-arm64-msvc": "16.2.0", "@next/swc-win32-x64-msvc": "16.2.0", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-NLBVrJy1pbV1Yn00L5sU4vFyAHt5XuSjzrNyFnxo6Com0M0KrL6hHM5B99dbqXb2bE9pm4Ow3Zl1xp6HVY9edQ=="], - "node-abi": ["node-abi@4.27.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-M6PypnnjGwr6Wv1O7twPpnJiie8MeLoBSh99zF1jnRRU2NLgxO/fUEQW1rfAhAKzPa/fvQ4PKitt1O+c8l243Q=="], + "node-abi": ["node-abi@4.28.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-Qfp5XZL1cJDOabOT8H5gnqMTmM4NjvYzHp4I/Kt/Sl76OVkOBBHRFlPspGV0hYvMoqQsypFjT/Yp7Km0beXW9g=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], @@ -3354,6 +3461,8 @@ "node-sarif-builder": ["node-sarif-builder@3.4.0", "", { "dependencies": { "@types/sarif": "^2.1.7", "fs-extra": "^11.1.1" } }, "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg=="], + "nofilter": ["nofilter@3.1.0", "", {}, "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g=="], + "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], "normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="], @@ -3392,7 +3501,7 @@ "oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="], - "oniguruma-to-es": ["oniguruma-to-es@4.3.4", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA=="], + "oniguruma-to-es": ["oniguruma-to-es@4.3.5", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ=="], "open": ["open@10.1.2", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw=="], @@ -3414,12 +3523,18 @@ "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], + "p-defer": ["p-defer@1.0.0", "", {}, "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw=="], + + "p-event": ["p-event@5.0.1", "", { "dependencies": { "p-timeout": "^5.0.2" } }, "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], "p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], + "p-timeout": ["p-timeout@5.1.0", "", {}, "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew=="], + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], @@ -3438,6 +3553,8 @@ "parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="], + "parse-ms": ["parse-ms@3.0.0", "", {}, "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw=="], + "parse-semver": ["parse-semver@1.1.1", "", { "dependencies": { "semver": "^5.1.0" } }, "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ=="], "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], @@ -3466,7 +3583,7 @@ "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], "path-type": ["path-type@6.0.0", "", {}, "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ=="], @@ -3486,6 +3603,8 @@ "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], + "pino": ["pino@10.3.1", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^3.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^4.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg=="], "pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="], @@ -3496,18 +3615,22 @@ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + "pkg-conf": ["pkg-conf@4.0.0", "", { "dependencies": { "find-up": "^6.0.0", "load-json-file": "^7.0.0" } }, "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w=="], + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], "pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="], "planck": ["planck@1.4.3", "", { "peerDependencies": { "stage-js": "^1.0.0-alpha.12" } }, "sha512-B+lHKhRSeg7vZOfEyEzyQVu7nx8JHcX3QgnAcHXrPW0j04XYKX5eXSiUrxH2Z5QR8OoqvjD6zKIaPMdMYAd0uA=="], - "playwright": ["playwright@1.58.2", "", { "dependencies": { "playwright-core": "1.58.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A=="], + "playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="], - "playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="], + "playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="], "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], + "plur": ["plur@5.1.0", "", { "dependencies": { "irregular-plurals": "^3.3.0" } }, "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg=="], + "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], "pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="], @@ -3522,7 +3645,7 @@ "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - "posthog-js": ["posthog-js@1.360.1", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.208.0", "@opentelemetry/exporter-logs-otlp-http": "^0.208.0", "@opentelemetry/resources": "^2.2.0", "@opentelemetry/sdk-logs": "^0.208.0", "@posthog/core": "1.23.3", "@posthog/types": "1.360.1", "core-js": "^3.38.1", "dompurify": "^3.3.2", "fflate": "^0.4.8", "preact": "^10.28.2", "query-selector-shadow-dom": "^1.0.1", "web-vitals": "^5.1.0" } }, "sha512-wtKZm0b0SLYLtk0T3SiyXn9cBhwE421fPcJUJ7cRpJmsysHKJcOJ9O/Q7nx7aDj6LvTFILuzjzYO3YTCjbWgqQ=="], + "posthog-js": ["posthog-js@1.362.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.208.0", "@opentelemetry/exporter-logs-otlp-http": "^0.208.0", "@opentelemetry/resources": "^2.2.0", "@opentelemetry/sdk-logs": "^0.208.0", "@posthog/core": "1.24.0", "@posthog/types": "1.362.0", "core-js": "^3.38.1", "dompurify": "^3.3.2", "fflate": "^0.4.8", "preact": "^10.28.2", "query-selector-shadow-dom": "^1.0.1", "web-vitals": "^5.1.0" } }, "sha512-qPHkAk9G19xVDAQLoQ1FOLNE9BBq+FDePhkOevbdUQcFJVNHVc+j7E/ndQ+olGnDuiSMdgAb5c6yGk7PD9Z0ug=="], "posthog-node": ["posthog-node@4.4.0", "", { "dependencies": { "axios": "^1.7.4" } }, "sha512-4FEFBuc4FDFkTEiCSIo7DFV0jpprlqfR/SzjVgg7E2rRvfxTW4J47IvCwSCo5C9lBeV0ujDubY/YArHG37aJIw=="], @@ -3540,6 +3663,8 @@ "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], + "pretty-ms": ["pretty-ms@8.0.0", "", { "dependencies": { "parse-ms": "^3.0.0" } }, "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q=="], + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], "proc-log": ["proc-log@5.0.0", "", {}, "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ=="], @@ -3648,9 +3773,9 @@ "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="], - "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="], @@ -3732,6 +3857,8 @@ "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + "sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="], + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -3760,13 +3887,13 @@ "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], - "simple-xml-to-json": ["simple-xml-to-json@1.2.3", "", {}, "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA=="], + "simple-xml-to-json": ["simple-xml-to-json@1.2.4", "", {}, "sha512-3MY16e0ocMHL7N1ufpdObURGyX+lCo0T/A+y6VCwosLdH1HSda4QZl1Sdt/O+2qWp48WFi26XEp5rF0LoaL0Dg=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], "slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="], - "slice-ansi": ["slice-ansi@4.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="], + "slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="], "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], @@ -3774,7 +3901,7 @@ "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], - "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], + "socket.io-parser": ["socket.io-parser@4.2.6", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg=="], "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], @@ -3832,6 +3959,8 @@ "sst-win32-x86": ["sst-win32-x86@3.18.10", "", { "os": "win32", "cpu": "none" }, "sha512-pq8SmV0pIjBFMY6DraUZ4akyTxHnfjIKCRbBLdMxFUZK8TzA1NK2YdjRt1AwrgXRYGRyctrz/mt4WyO0SMOVQQ=="], + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], "stage-js": ["stage-js@1.0.1", "", {}, "sha512-cz14aPp/wY0s3bkb/B93BPP5ZAEhgBbRmAT3CCDqert8eCAqIpQ0RB2zpK8Ksxf+Pisl5oTzvPHtL4CVzzeHcw=="], @@ -3888,6 +4017,8 @@ "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="], + "supertap": ["supertap@3.0.1", "", { "dependencies": { "indent-string": "^5.0.0", "js-yaml": "^3.14.1", "serialize-error": "^7.0.1", "strip-ansi": "^7.0.1" } }, "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw=="], + "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], "supports-hyperlinks": ["supports-hyperlinks@3.2.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig=="], @@ -3898,7 +4029,7 @@ "table": ["table@6.9.0", "", { "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1" } }, "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A=="], - "tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], + "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], @@ -3916,6 +4047,8 @@ "temp": ["temp@0.9.4", "", { "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" } }, "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA=="], + "temp-dir": ["temp-dir@3.0.0", "", {}, "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw=="], + "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="], "terminal-link": ["terminal-link@4.0.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "supports-hyperlinks": "^3.2.0" } }, "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA=="], @@ -3934,6 +4067,8 @@ "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], + "time-zone": ["time-zone@1.0.0", "", {}, "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA=="], + "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "^5.5.0" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], @@ -3958,6 +4093,8 @@ "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], + "to-buffer": ["to-buffer@1.2.2", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="], @@ -3988,25 +4125,23 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], - "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.5.6", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.6", "turbo-darwin-arm64": "2.5.6", "turbo-linux-64": "2.5.6", "turbo-linux-arm64": "2.5.6", "turbo-windows-64": "2.5.6", "turbo-windows-arm64": "2.5.6" }, "bin": { "turbo": "bin/turbo" } }, "sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w=="], + "turbo": ["turbo@2.8.13", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.13", "turbo-darwin-arm64": "2.8.13", "turbo-linux-64": "2.8.13", "turbo-linux-arm64": "2.8.13", "turbo-windows-64": "2.8.13", "turbo-windows-arm64": "2.8.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A=="], - "turbo-darwin-64": ["turbo-darwin-64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A=="], + "turbo-darwin-64": ["turbo-darwin-64@2.8.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ=="], - "turbo-linux-64": ["turbo-linux-64@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA=="], + "turbo-linux-64": ["turbo-linux-64@2.8.13", "", { "os": "linux", "cpu": "x64" }, "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.8.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg=="], - "turbo-windows-64": ["turbo-windows-64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg=="], + "turbo-windows-64": ["turbo-windows-64@2.8.13", "", { "os": "win32", "cpu": "x64" }, "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA=="], - "turbo-windows-arm64": ["turbo-windows-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q=="], + "turbo-windows-arm64": ["turbo-windows-arm64@2.8.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA=="], "turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="], @@ -4016,11 +4151,13 @@ "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + "typed-rest-client": ["typed-rest-client@1.8.11", "", { "dependencies": { "qs": "^6.9.1", "tunnel": "0.0.6", "underscore": "^1.12.1" } }, "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA=="], "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], - "typescript-eslint": ["typescript-eslint@8.57.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.57.0", "@typescript-eslint/parser": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA=="], + "typescript-eslint": ["typescript-eslint@8.57.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.57.1", "@typescript-eslint/parser": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1", "@typescript-eslint/utils": "8.57.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA=="], "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], @@ -4080,6 +4217,8 @@ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], + "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], "v8-to-istanbul": ["v8-to-istanbul@9.3.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" } }, "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA=="], @@ -4136,6 +4275,8 @@ "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + "well-known-symbols": ["well-known-symbols@2.0.0", "", {}, "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q=="], + "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], @@ -4144,7 +4285,7 @@ "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="], - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], @@ -4162,6 +4303,8 @@ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], + "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], @@ -4180,6 +4323,8 @@ "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], + "yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], "yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], @@ -4208,7 +4353,7 @@ "@actions/github/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], - "@actions/http-client/undici": ["undici@6.24.0", "", {}, "sha512-lVLNosgqo5EkGqh5XUDhGfsMSoO8K0BAN0TyJLvwNRSl4xWGZlCVYsAIpa/OpA3TvmnM01GWcoKmc3ZWo5wKKA=="], + "@actions/http-client/undici": ["undici@6.24.1", "", {}, "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA=="], "@ai-sdk/amazon-bedrock/aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], @@ -4248,71 +4393,71 @@ "@ai-sdk/xai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], - "@antfu/install-pkg/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "@antfu/install-pkg/tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="], - "@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-crypto/crc32c/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-crypto/crc32c/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-crypto/sha1-browser/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-crypto/sha1-browser/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-crypto/sha256-browser/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-crypto/sha256-browser/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-crypto/sha256-js/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-crypto/sha256-js/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-crypto/util/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-crypto/util/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@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-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.20", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.17", "@aws-sdk/credential-provider-http": "^3.972.19", "@aws-sdk/credential-provider-ini": "^3.972.19", "@aws-sdk/credential-provider-process": "^3.972.17", "@aws-sdk/credential-provider-sso": "^3.972.19", "@aws-sdk/credential-provider-web-identity": "^3.972.19", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-0xHca2BnPY0kzjDYPH7vk8YbfdBPpWVS67rtqQMalYDQUCBYS37cZ55K6TuFxCoIyNZgSCFrVKr9PXC5BVvQQw=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.22", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.19", "@aws-sdk/credential-provider-http": "^3.972.21", "@aws-sdk/credential-provider-ini": "^3.972.21", "@aws-sdk/credential-provider-process": "^3.972.19", "@aws-sdk/credential-provider-sso": "^3.972.21", "@aws-sdk/credential-provider-web-identity": "^3.972.21", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-VE6i8nkmrRyhKut7nnfCWRbdDf+CfyRr8ixSwdaPDguYlgvkAO2pHu9oK11XzbSuatB0io1ozI/vpYhelXn8Pg=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@aws-sdk/client-cognito-identity/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.993.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.19", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.6", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.9", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-retry": "^4.4.40", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.39", "@smithy/util-defaults-mode-node": "^4.2.42", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.21", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.8", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-env/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-env/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-provider-http/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-http/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-http/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-http/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.19", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.6", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.9", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-retry": "^4.4.40", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.39", "@smithy/util-defaults-mode-node": "^4.2.42", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.21", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.8", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-provider-login/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.19", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.6", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.9", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-retry": "^4.4.40", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.39", "@smithy/util-defaults-mode-node": "^4.2.42", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.21", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.8", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ=="], - "@aws-sdk/credential-provider-login/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-login/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@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=="], @@ -4326,55 +4471,53 @@ "@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=="], - "@aws-sdk/credential-provider-process/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-process/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-process/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.19", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.6", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.9", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-retry": "^4.4.40", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.39", "@smithy/util-defaults-mode-node": "^4.2.42", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.21", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.8", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.19", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.6", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.9", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-retry": "^4.4.40", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.39", "@smithy/util-defaults-mode-node": "^4.2.42", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.21", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.8", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/credential-providers/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-providers/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-providers/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.20", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.17", "@aws-sdk/credential-provider-http": "^3.972.19", "@aws-sdk/credential-provider-ini": "^3.972.19", "@aws-sdk/credential-provider-process": "^3.972.17", "@aws-sdk/credential-provider-sso": "^3.972.19", "@aws-sdk/credential-provider-web-identity": "^3.972.19", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-0xHca2BnPY0kzjDYPH7vk8YbfdBPpWVS67rtqQMalYDQUCBYS37cZ55K6TuFxCoIyNZgSCFrVKr9PXC5BVvQQw=="], + "@aws-sdk/credential-providers/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.22", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.19", "@aws-sdk/credential-provider-http": "^3.972.21", "@aws-sdk/credential-provider-ini": "^3.972.21", "@aws-sdk/credential-provider-process": "^3.972.19", "@aws-sdk/credential-provider-sso": "^3.972.21", "@aws-sdk/credential-provider-web-identity": "^3.972.21", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-VE6i8nkmrRyhKut7nnfCWRbdDf+CfyRr8ixSwdaPDguYlgvkAO2pHu9oK11XzbSuatB0io1ozI/vpYhelXn8Pg=="], - "@aws-sdk/credential-providers/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/credential-providers/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], - "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.993.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw=="], - "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], - "@aws-sdk/token-providers/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/token-providers/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.19", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.6", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.9", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-retry": "^4.4.40", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.39", "@smithy/util-defaults-mode-node": "^4.2.42", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.21", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.8", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ=="], - "@aws-sdk/token-providers/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], - - "@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/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@azure/core-http/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="], @@ -4442,7 +4585,7 @@ "@gitlab/gitlab-ai-provider/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.71.2", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ=="], - "@gitlab/gitlab-ai-provider/openai": ["openai@6.27.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ=="], + "@gitlab/gitlab-ai-provider/openai": ["openai@6.32.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-j3k+BjydAf8yQlcOI7WUQMQTbbF5GEIMAE2iZYCOzwwB3S2pCheaWYp+XZRNAch4jWVc52PMDGRRjutao3lLCg=="], "@gitlab/gitlab-ai-provider/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -4488,6 +4631,8 @@ "@jimp/types/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@kilocode/cli/@morphllm/morphsdk": ["@morphllm/morphsdk@0.2.148", "", { "dependencies": { "@vscode/ripgrep": "^1.17.0", "ai": ">=5.0.0", "diff": "^7.0.0", "isomorphic-git": "^1.25.10", "openai": "^4.52.7", "zod": ">=3.23.0" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.25.0", "@google/generative-ai": ">=0.21.0" }, "optionalPeers": ["@anthropic-ai/sdk", "@google/generative-ai"] }, "sha512-pIABC+KR9yR567wyBGNhDEjNDR11V2CY6a2caosA5yYTP1Me0freUA4BCIfw71o7YG3I9LU1i+ZG1+vZ0Cv8dw=="], + "@kilocode/kilo-docs/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "@kilocode/kilo-gateway/@opentui/core": ["@opentui/core@0.1.75", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.75", "@opentui/core-darwin-x64": "0.1.75", "@opentui/core-linux-arm64": "0.1.75", "@opentui/core-linux-x64": "0.1.75", "@opentui/core-win32-arm64": "0.1.75", "@opentui/core-win32-x64": "0.1.75", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-8ARRZxSG+BXkJmEVtM2DQ4se7DAF1ZCKD07d+AklgTr2mxCzmdxxPbOwRzboSQ6FM7qGuTVPVbV4O2W9DpUmoA=="], @@ -4500,6 +4645,8 @@ "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + "@morphllm/morphsdk/diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], + "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "@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=="], @@ -4540,8 +4687,6 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], - "@opencode-ai/app/@playwright/test": ["@playwright/test@1.57.0", "", { "dependencies": { "playwright": "1.57.0" }, "bin": { "playwright": "cli.js" } }, "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA=="], - "@opencode-ai/app/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="], "@opencode-ai/app/tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="], @@ -4562,15 +4707,15 @@ "@opencode-ai/desktop-electron/vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="], - "@opencode-ai/storybook/@storybook/addon-a11y": ["@storybook/addon-a11y@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.2.18" } }, "sha512-ysAPbCNqKEzei+PAUYuloV//STabW/wEkMcpx3VA74iNzw6oHf7nI270m7kCpYMHmu0uDYGvvb9z/0rZyV2ADw=="], + "@opencode-ai/storybook/@storybook/addon-a11y": ["@storybook/addon-a11y@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.3.0" } }, "sha512-GOQP8kp0Pos3weW00U5FC2azt1zZQOcyihP+tINQO6/MDA3hts0rKMbS5+MyVULX7A5JE5uk7SzcZQj+EZ8Yrg=="], - "@opencode-ai/storybook/@storybook/addon-docs": ["@storybook/addon-docs@10.2.18", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.2.18", "@storybook/icons": "^2.0.1", "@storybook/react-dom-shim": "10.2.18", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.2.18" } }, "sha512-9nFpeuxYosSOvir3zdcbfyozwQWqqAKrrc0ikqBIZN+mpYdmbPWYdAWCI/YjV06EY5uWEVwGucXUXPCxUvP6NQ=="], + "@opencode-ai/storybook/@storybook/addon-docs": ["@storybook/addon-docs@10.3.0", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.3.0", "@storybook/icons": "^2.0.1", "@storybook/react-dom-shim": "10.3.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.3.0" } }, "sha512-g9bc4YDiy4g/peLsUDmVcy2q/QXI3eHCQtHrVp2sHWef2SYjwUJ2+TOtJHScO8LuKhGnU3h2UeE59tPWTF2quw=="], "@opencode-ai/storybook/@types/react": ["@types/react@18.0.25", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g=="], "@opencode-ai/storybook/react": ["react@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ=="], - "@opencode-ai/storybook/storybook": ["storybook@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-1kF8QV/F+Qq2WVHYPTtDJltG9UVOS4PAArf6lmtMt/QbCzYYlLiHHnjZZuFpbDHUSh0SIC6G/97GJ3+HcJHRdg=="], + "@opencode-ai/storybook/storybook": ["storybook@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-OpLdng98l7cACuqBoQwewx21Vhgl9XPssgLdXQudW0+N5QPjinWXZpZCquZpXpNCyw5s5BFAcv+jKB3Qkf9jeA=="], "@opencode-ai/storybook/vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="], @@ -4618,15 +4763,19 @@ "@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=="], - "@storybook/addon-links/storybook": ["storybook@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-1kF8QV/F+Qq2WVHYPTtDJltG9UVOS4PAArf6lmtMt/QbCzYYlLiHHnjZZuFpbDHUSh0SIC6G/97GJ3+HcJHRdg=="], + "@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], - "@storybook/addon-onboarding/storybook": ["storybook@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-1kF8QV/F+Qq2WVHYPTtDJltG9UVOS4PAArf6lmtMt/QbCzYYlLiHHnjZZuFpbDHUSh0SIC6G/97GJ3+HcJHRdg=="], + "@solid-primitives/scroll/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], - "@storybook/addon-vitest/storybook": ["storybook@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-1kF8QV/F+Qq2WVHYPTtDJltG9UVOS4PAArf6lmtMt/QbCzYYlLiHHnjZZuFpbDHUSh0SIC6G/97GJ3+HcJHRdg=="], + "@storybook/addon-links/storybook": ["storybook@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-OpLdng98l7cACuqBoQwewx21Vhgl9XPssgLdXQudW0+N5QPjinWXZpZCquZpXpNCyw5s5BFAcv+jKB3Qkf9jeA=="], - "@storybook/builder-vite/@storybook/csf-plugin": ["@storybook/csf-plugin@10.2.18", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.2.18", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-JWJ39Dh3WVTt74fb+GNFnEY+4G394UQ6pAidc7FWeE7OfMPDWFZnMgLxE6oR2GMHm7Gc74yvD3g/EbWaJrOHsw=="], + "@storybook/addon-onboarding/storybook": ["storybook@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-OpLdng98l7cACuqBoQwewx21Vhgl9XPssgLdXQudW0+N5QPjinWXZpZCquZpXpNCyw5s5BFAcv+jKB3Qkf9jeA=="], - "@storybook/builder-vite/storybook": ["storybook@10.2.18", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-1kF8QV/F+Qq2WVHYPTtDJltG9UVOS4PAArf6lmtMt/QbCzYYlLiHHnjZZuFpbDHUSh0SIC6G/97GJ3+HcJHRdg=="], + "@storybook/addon-vitest/storybook": ["storybook@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-OpLdng98l7cACuqBoQwewx21Vhgl9XPssgLdXQudW0+N5QPjinWXZpZCquZpXpNCyw5s5BFAcv+jKB3Qkf9jeA=="], + + "@storybook/builder-vite/@storybook/csf-plugin": ["@storybook/csf-plugin@10.3.0", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.3.0", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-zlBnNpv0wtmICdQPDoY91HNzn6BNqnS2hur580J+qJtcP+5ZOYU7+gNyU+vfAnQuLEWbPz34rx8b1cTzXZQCDg=="], + + "@storybook/builder-vite/storybook": ["storybook@10.3.0", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-OpLdng98l7cACuqBoQwewx21Vhgl9XPssgLdXQudW0+N5QPjinWXZpZCquZpXpNCyw5s5BFAcv+jKB3Qkf9jeA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w=="], @@ -4702,6 +4851,20 @@ "archiver-utils/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + "ava/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "ava/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=="], + + "ava/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + + "ava/globby": ["globby@13.2.2", "", { "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.3.0", "ignore": "^5.2.4", "merge2": "^1.4.1", "slash": "^4.0.0" } }, "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w=="], + + "ava/p-map": ["p-map@5.5.0", "", { "dependencies": { "aggregate-error": "^4.0.0" } }, "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg=="], + + "ava/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "ava/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "aws-sdk/events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="], "aws-sdk/uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], @@ -4716,7 +4879,7 @@ "builder-util/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "builder-util-runtime/sax": ["sax@1.5.0", "", {}, "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA=="], + "builder-util-runtime/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], @@ -4734,13 +4897,13 @@ "cacheable-request/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], - "cheerio/undici": ["undici@7.24.0", "", {}, "sha512-jxytwMHhsbdpBXxLAcuu0fzlQeXCNnWdDyRHpvWsUl8vd98UwYdl9YTyn8/HcpcJPC3pwUveefsa3zTxyD/ERg=="], + "cheerio/undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="], "cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], - "cli-truncate/slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], + "clean-stack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - "cli-truncate/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=="], + "cli-truncate/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=="], "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], @@ -4750,6 +4913,8 @@ "crc/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="], "d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], @@ -4762,6 +4927,8 @@ "dir-compare/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "dir-glob/path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + "dmg-builder/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "dmg-license/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], @@ -4802,28 +4969,40 @@ "fetch-blob/web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + "figures/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "figures/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], + "filelist/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="], "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "framer-motion/motion-dom": ["motion-dom@12.36.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-Ep1pq8P88rGJ75om8lTCA13zqd7ywPGwCqwuWwin6BKc0hMLkVfcS6qKlRqEo2+t0DwoUcgGJfXwaiFn4AOcQA=="], + "framer-motion/motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], "framer-motion/motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], + "friendly-words/express": ["express@4.22.1", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.3", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], + "fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + "global-agent/matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], "http2-wrapper/quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="], + "iconv-corefoundation/cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], + "iconv-corefoundation/node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], + "isomorphic-git/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + "istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "jszip/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], @@ -4860,6 +5039,8 @@ "markdown-it/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "matcher/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + "mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -4898,7 +5079,7 @@ "nypm/citty": ["citty@0.2.1", "", {}, "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg=="], - "nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "nypm/tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="], "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], @@ -4918,12 +5099,16 @@ "ora/log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], + "parent-module/callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + "parse-semver/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "pixelmatch/pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="], + "pkg-conf/find-up": ["find-up@6.3.0", "", { "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" } }, "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw=="], + "pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "pkg-up/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], @@ -4940,7 +5125,7 @@ "prebuild-install/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "prebuild-install/node-abi": ["node-abi@3.88.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-At6b4UqIEVudaqPsXjmUO1r/N5BUr4yhDGs5PkBE8/oG5+TfLPhFechiskFsnT6Ql0VfUXbalUUCbfXxtj7K+w=="], + "prebuild-install/node-abi": ["node-abi@3.89.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA=="], "pretty-format/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -4960,10 +5145,16 @@ "readdir-glob/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="], + "redent/indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], "sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], @@ -4972,6 +5163,12 @@ "shiki/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], + "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="], + + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + "storybook/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -4982,8 +5179,12 @@ "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + "supertap/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + "supports-hyperlinks/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "table/slice-ansi": ["slice-ansi@4.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="], + "table/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=="], "table/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -5002,6 +5203,8 @@ "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + "to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "tree-sitter-bash/node-addon-api": ["node-addon-api@8.6.0", "", {}, "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q=="], @@ -5024,7 +5227,7 @@ "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "xml2js/sax": ["sax@1.5.0", "", {}, "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA=="], + "xml2js/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], "yargs-unparser/decamelize": ["decamelize@4.0.0", "", {}, "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="], @@ -5042,67 +5245,67 @@ "@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.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.973.19", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.9", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.973.21", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.12", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], - "@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], - "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], "@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=="], @@ -5110,67 +5313,67 @@ "@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=="], - "@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], - "@aws-sdk/credential-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.19", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.9", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.21", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.6", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.20", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ=="], + "@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.8", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ=="], "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -5220,6 +5423,8 @@ "@hey-api/openapi-ts/open/wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="], + "@kilocode/cli/@morphllm/morphsdk/diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], + "@kilocode/kilo-gateway/@opentui/core/@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.75", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gGaGZjkFpqcXJk6321JzhRl66pM2VxBlI470L8W4DQUW4S6iDT1R9L7awSzGB4Cn9toUl7DTV8BemaXZYXV4SA=="], "@kilocode/kilo-gateway/@opentui/core/@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.75", "", { "os": "darwin", "cpu": "x64" }, "sha512-tPlvqQI0whZ76amHydpJs5kN+QeWAIcFbI8RAtlAo9baj2EbxTDC+JGwgb9Fnt0/YQx831humbtaNDhV2Jt1bw=="], @@ -5272,7 +5477,7 @@ "@octokit/rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], - "@opencode-ai/app/@playwright/test/playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="], + "@opencode-ai/app/@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], "@opencode-ai/app/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=="], @@ -5284,9 +5489,9 @@ "@opencode-ai/desktop/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=="], - "@opencode-ai/storybook/@storybook/addon-docs/@storybook/csf-plugin": ["@storybook/csf-plugin@10.2.18", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.2.18", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-JWJ39Dh3WVTt74fb+GNFnEY+4G394UQ6pAidc7FWeE7OfMPDWFZnMgLxE6oR2GMHm7Gc74yvD3g/EbWaJrOHsw=="], + "@opencode-ai/storybook/@storybook/addon-docs/@storybook/csf-plugin": ["@storybook/csf-plugin@10.3.0", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.3.0", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-zlBnNpv0wtmICdQPDoY91HNzn6BNqnS2hur580J+qJtcP+5ZOYU7+gNyU+vfAnQuLEWbPz34rx8b1cTzXZQCDg=="], - "@opencode-ai/storybook/@storybook/addon-docs/@storybook/react-dom-shim": ["@storybook/react-dom-shim@10.2.18", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.2.18" } }, "sha512-LhVH5oTknCEF4cG5LDM81O1G/bzD15/lbsS6iqtJDqWsncrukwiUweA0uoRp2Uoc3E3/wW2qHs81sdLBi3qsMQ=="], + "@opencode-ai/storybook/@storybook/addon-docs/@storybook/react-dom-shim": ["@storybook/react-dom-shim@10.3.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.3.0" } }, "sha512-dmAnIjkMmUYZCdg3FUL83Lavybin3bYKRNRXFZq1okCH8SINa2J+zKEzJhPlqixAKkbd7x1PFDgXnxxM/Nisig=="], "@opencode-ai/storybook/@storybook/addon-docs/react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], @@ -5294,6 +5499,8 @@ "@opencode-ai/storybook/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=="], + "@opencode-ai/ui/@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], + "@opencode-ai/ui/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=="], "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], @@ -5406,7 +5613,19 @@ "archiver-utils/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "aws-sdk/xml2js/sax": ["sax@1.5.0", "", {}, "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA=="], + "ava/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "ava/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "ava/globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "ava/globby/slash": ["slash@4.0.0", "", {}, "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew=="], + + "ava/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "ava/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ava/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.7", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg=="], @@ -5430,15 +5649,13 @@ "cacache/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "cli-truncate/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "cli-truncate/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "cli-truncate/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "crc/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "d3-sankey/d3-array/internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], + "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], @@ -5572,8 +5789,36 @@ "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "friendly-words/express/accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + + "friendly-words/express/body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="], + + "friendly-words/express/content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], + + "friendly-words/express/cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="], + + "friendly-words/express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "friendly-words/express/finalhandler": ["finalhandler@1.3.2", "", { "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.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="], + + "friendly-words/express/fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "friendly-words/express/merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], + + "friendly-words/express/qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="], + + "friendly-words/express/send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], + + "friendly-words/express/serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], + + "friendly-words/express/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "iconv-corefoundation/cli-truncate/slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], + + "iconv-corefoundation/cli-truncate/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=="], + "jszip/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -5612,6 +5857,10 @@ "ora/log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], + "pkg-conf/find-up/locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="], + + "pkg-conf/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], + "pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], "posthog-js/@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.6.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg=="], @@ -5636,6 +5885,8 @@ "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "supertap/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "table/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "table/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -5664,31 +5915,31 @@ "@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.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ=="], - "@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], "@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.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/credential-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], - "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], "@electron/asar/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -5728,10 +5979,6 @@ "@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@opencode-ai/app/@playwright/test/playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], - - "@opencode-ai/app/@playwright/test/playwright/playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="], - "@opencode-ai/app/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], "@opencode-ai/app/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], @@ -6052,6 +6299,14 @@ "archiver-utils/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "ava/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ava/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ava/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "ava/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "babel-plugin-module-resolver/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -6070,8 +6325,6 @@ "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "dir-compare/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "electron-builder/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -6086,8 +6339,26 @@ "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "friendly-words/express/accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "friendly-words/express/accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + + "friendly-words/express/body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "friendly-words/express/body-parser/raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="], + + "friendly-words/express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "friendly-words/express/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + + "friendly-words/express/type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "gray-matter/js-yaml/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "iconv-corefoundation/cli-truncate/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "iconv-corefoundation/cli-truncate/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "mocha/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], "mocha/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -6102,6 +6373,8 @@ "mocha/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "pkg-conf/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="], + "pkg-up/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], "pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], @@ -6122,6 +6395,8 @@ "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "supertap/js-yaml/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "tar-fs/tar-stream/bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "test-exclude/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], @@ -6130,7 +6405,7 @@ "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="], + "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.6", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.1.3", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw=="], "@electron/rebuild/ora/bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], @@ -6158,6 +6433,12 @@ "archiver-utils/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "ava/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ava/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ava/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "babel-plugin-module-resolver/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "c8/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -6174,6 +6455,12 @@ "electron-builder/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "friendly-words/express/accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "friendly-words/express/type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "iconv-corefoundation/cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "mocha/glob/jackspeak/@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=="], "mocha/glob/jackspeak/@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=="], @@ -6182,6 +6469,8 @@ "mocha/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "pkg-conf/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], + "pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "qrcode/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -6218,6 +6507,8 @@ "mocha/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "pkg-conf/find-up/locate-path/p-locate/p-limit/yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], + "qrcode/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "test-exclude/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], diff --git a/flake.lock b/flake.lock index 80484256d69..d98f5a271f4 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1772956932, - "narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=", + "lastModified": 1773628058, + "narHash": "sha256-hpXH0z3K9xv0fHaje136KY872VT2T5uwxtezlAskQgY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "608d0cadfed240589a7eea422407a547ad626a14", + "rev": "f8573b9c935cfaa162dd62cc9e75ae2db86f85df", "type": "github" }, "original": { diff --git a/nix/hashes.json b/nix/hashes.json index 6ea6b6b344a..8d54b85cb0c 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-2SnZbJPIvgCkb4jNh49CnbDAOpghgO9XihSiTlL6rYI=", - "aarch64-linux": "sha256-HV/Sm4rBAZPjxG+SQJ95634yTyJXDjlSeYemMYg8eCE=", - "aarch64-darwin": "sha256-PAJSd1VkNc7LUSrOAeG+rmYUw8VefR8GfkAIy8H3iV0=", - "x86_64-darwin": "sha256-Qdk8nu4FoGjp6+7Ji5vuHw2HhM1Z+ivE7meqJivTiHk=" + "x86_64-linux": "sha256-85Pa4C5F3yqjMzIGBcWYGe+IitSg9nnTtixqZPRnFps=", + "aarch64-linux": "sha256-qeyu0LS1z8JXGa+2EVd/U94uQIV8zi53ZmymE9/trSU=", + "aarch64-darwin": "sha256-qwedJnAMcM/gTVSCTErsP++HM2lYQtLE+PM1QkT7fy8=", + "x86_64-darwin": "sha256-372zLuwN6TLhn4JIDorEc13mjMpC91UbukxE/Y14c/k=" } } diff --git a/nix/node_modules.nix b/nix/node_modules.nix index 98bfbae5bdd..0041d45e443 100644 --- a/nix/node_modules.nix +++ b/nix/node_modules.nix @@ -31,7 +31,6 @@ stdenvNoCC.mkDerivation { ../package.json ../patches ../install # required by desktop build (cli.rs include_str!) - ../.github/TEAM_MEMBERS # required by @opencode-ai/script ] ); }; diff --git a/package.json b/package.json index e350051098c..dba58cb6a59 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "prepare": "husky", "random": "echo 'Random script'", "hello": "echo 'Hello World!'", - "test": "echo 'do not run tests from root' && exit 1" + "test": "echo 'do not run tests from root' && exit 1", + "extension": "bun --cwd packages/kilo-vscode script/launch.ts" }, "workspaces": { "packages": [ @@ -39,8 +40,8 @@ "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "ai": "5.0.124", "hono": "4.10.7", "hono-openapi": "1.1.2", @@ -50,7 +51,7 @@ "marked-shiki": "1.2.1", "@playwright/test": "1.51.0", "typescript": "5.8.2", - "@typescript/native-preview": "7.0.0-dev.20251207.1", + "@typescript/native-preview": "7.0.0-dev.20260316.1", "zod": "4.1.8", "remeda": "2.26.0", "shiki": "3.20.0", @@ -69,19 +70,21 @@ "@actions/artifact": "5.0.1", "@tsconfig/bun": "catalog:", "@types/mime-types": "3.0.1", + "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.5.6" + "turbo": "2.8.13" }, "dependencies": { "@aws-sdk/client-s3": "3.933.0", "@kilocode/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@kilocode/sdk": "workspace:*", - "typescript": "catalog:" + "typescript": "catalog:", + "@morphllm/morphsdk": "0.2.141" }, "repository": { "type": "git", @@ -109,6 +112,6 @@ "@openrouter/ai-sdk-provider@1.5.4": "patches/@openrouter%2Fai-sdk-provider@1.5.4.patch", "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch" }, - "version": "7.0.47", + "version": "7.1.3", "peerDependencies": {} } diff --git a/packages/app/e2e/AGENTS.md b/packages/app/e2e/AGENTS.md index 59662dbea56..8bfbd111b25 100644 --- a/packages/app/e2e/AGENTS.md +++ b/packages/app/e2e/AGENTS.md @@ -71,6 +71,12 @@ test("test description", async ({ page, sdk, gotoSession }) => { - `closeDialog(page, dialog)` - Close any dialog - `openSidebar(page)` / `closeSidebar(page)` - Toggle sidebar - `withSession(sdk, title, callback)` - Create temp session +- `withProject(...)` - Create temp project/workspace +- `sessionIDFromUrl(url)` - Read session ID from URL +- `slugFromUrl(url)` - Read workspace slug from URL +- `waitSlug(page, skip?)` - Wait for resolved workspace slug +- `trackSession(sessionID, directory?)` - Register session for fixture cleanup +- `trackDirectory(directory)` - Register directory for fixture cleanup - `clickListItem(container, filter)` - Click list item by key/text **Selectors** (`selectors.ts`): @@ -109,7 +115,7 @@ import { test, expect } from "@playwright/test" ### Error Handling -Tests should clean up after themselves: +Tests should clean up after themselves. Prefer fixture-managed cleanup: ```typescript test("test with cleanup", async ({ page, sdk, gotoSession }) => { @@ -120,6 +126,11 @@ test("test with cleanup", async ({ page, sdk, gotoSession }) => { }) ``` +- Prefer `withSession(...)` for temp sessions +- In `withProject(...)` tests that create sessions or extra workspaces, call `trackSession(sessionID, directory?)` and `trackDirectory(directory)` +- This lets fixture teardown abort, wait for idle, and clean up safely under CI concurrency +- Avoid calling `sdk.session.delete(...)` directly + ### Timeouts Default: 60s per test, 10s per assertion. Override when needed: @@ -161,9 +172,10 @@ await page.keyboard.press(`${modKey}+Comma`) // Open settings 1. Choose appropriate folder or create new one 2. Import from `../fixtures` 3. Use helper functions from `../actions` and `../selectors` -4. Clean up any created resources -5. Use specific selectors (avoid CSS classes) -6. Test one feature per test file +4. When validating routing, use shared helpers from `../actions`. Workspace URL slugs can be canonicalized on Windows, so assert against canonical or resolved workspace slugs. +5. Clean up any created resources +6. Use specific selectors (avoid CSS classes) +7. Test one feature per test file ## Local Development diff --git a/packages/app/e2e/actions.ts b/packages/app/e2e/actions.ts index f13ff63cd22..bcd0a1b5cab 100644 --- a/packages/app/e2e/actions.ts +++ b/packages/app/e2e/actions.ts @@ -3,12 +3,12 @@ import fs from "node:fs/promises" import os from "node:os" import path from "node:path" import { execSync } from "node:child_process" -import { modKey, serverUrl } from "./utils" +import { createSdk, modKey, resolveDirectory, serverUrl } from "./utils" import { - sessionItemSelector, dropdownMenuTriggerSelector, dropdownMenuContentSelector, projectMenuTriggerSelector, + projectCloseMenuSelector, projectWorkspacesToggleSelector, titlebarRightSelector, popoverBodySelector, @@ -18,7 +18,6 @@ import { workspaceItemSelector, workspaceMenuTriggerSelector, } from "./selectors" -import type { createSdk } from "./utils" export async function defocus(page: Page) { await page @@ -61,9 +60,9 @@ export async function closeDialog(page: Page, dialog: Locator) { } export async function isSidebarClosed(page: Page) { - const main = page.locator("main") - const classes = (await main.getAttribute("class")) ?? "" - return classes.includes("xl:border-l") + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() + await expect(button).toBeVisible() + return (await button.getAttribute("aria-expanded")) !== "true" } export async function toggleSidebar(page: Page) { @@ -75,48 +74,34 @@ export async function openSidebar(page: Page) { if (!(await isSidebarClosed(page))) return const button = page.getByRole("button", { name: /toggle sidebar/i }).first() - const visible = await button - .isVisible() - .then((x) => x) - .catch(() => false) + await button.click() - if (visible) await button.click() - if (!visible) await toggleSidebar(page) - - const main = page.locator("main") - const opened = await expect(main) - .not.toHaveClass(/xl:border-l/, { timeout: 1500 }) + const opened = await expect(button) + .toHaveAttribute("aria-expanded", "true", { timeout: 1500 }) .then(() => true) .catch(() => false) if (opened) return await toggleSidebar(page) - await expect(main).not.toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "true") } export async function closeSidebar(page: Page) { if (await isSidebarClosed(page)) return const button = page.getByRole("button", { name: /toggle sidebar/i }).first() - const visible = await button - .isVisible() - .then((x) => x) - .catch(() => false) + await button.click() - if (visible) await button.click() - if (!visible) await toggleSidebar(page) - - const main = page.locator("main") - const closed = await expect(main) - .toHaveClass(/xl:border-l/, { timeout: 1500 }) + const closed = await expect(button) + .toHaveAttribute("aria-expanded", "false", { timeout: 1500 }) .then(() => true) .catch(() => false) if (closed) return await toggleSidebar(page) - await expect(main).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") } export async function openSettings(page: Page) { @@ -197,17 +182,48 @@ export async function createTestProject() { await fs.writeFile(path.join(root, "README.md"), "# e2e\n") execSync("git init", { cwd: root, stdio: "ignore" }) + execSync("git config core.fsmonitor false", { cwd: root, stdio: "ignore" }) execSync("git add -A", { cwd: root, stdio: "ignore" }) execSync('git -c user.name="e2e" -c user.email="e2e@example.com" commit -m "init" --allow-empty', { cwd: root, stdio: "ignore", }) - return root + return resolveDirectory(root) } export async function cleanupTestProject(directory: string) { - await fs.rm(directory, { recursive: true, force: true }).catch(() => undefined) + try { + execSync("git fsmonitor--daemon stop", { cwd: directory, stdio: "ignore" }) + } catch {} + await fs.rm(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }).catch(() => undefined) +} + +export function slugFromUrl(url: string) { + return /\/([^/]+)\/session(?:[/?#]|$)/.exec(url)?.[1] ?? "" +} + +export async function waitSlug(page: Page, skip: string[] = []) { + let prev = "" + let next = "" + await expect + .poll( + () => { + const slug = slugFromUrl(page.url()) + if (!slug) return "" + if (skip.includes(slug)) return "" + if (slug !== prev) { + prev = slug + next = "" + return "" + } + next = slug + return slug + }, + { timeout: 45_000 }, + ) + .not.toBe("") + return next } export function sessionIDFromUrl(url: string) { @@ -216,7 +232,7 @@ export function sessionIDFromUrl(url: string) { } export async function hoverSessionItem(page: Page, sessionID: string) { - const sessionEl = page.locator(sessionItemSelector(sessionID)).first() + const sessionEl = page.locator(`[data-session-id="${sessionID}"]`).last() await expect(sessionEl).toBeVisible() await sessionEl.hover() return sessionEl @@ -320,6 +336,57 @@ export async function clickListItem( return item } +async function status(sdk: ReturnType, sessionID: string) { + const data = await sdk.session + .status() + .then((x) => x.data ?? {}) + .catch(() => undefined) + return data?.[sessionID] +} + +async function stable(sdk: ReturnType, sessionID: string, timeout = 10_000) { + let prev = "" + await expect + .poll( + async () => { + const info = await sdk.session + .get({ sessionID }) + .then((x) => x.data) + .catch(() => undefined) + if (!info) return true + const next = `${info.title}:${info.time.updated ?? info.time.created}` + if (next !== prev) { + prev = next + return false + } + return true + }, + { timeout }, + ) + .toBe(true) +} + +export async function waitSessionIdle(sdk: ReturnType, sessionID: string, timeout = 30_000) { + await expect.poll(() => status(sdk, sessionID).then((x) => !x || x.type === "idle"), { timeout }).toBe(true) +} + +export async function cleanupSession(input: { + sessionID: string + directory?: string + sdk?: ReturnType +}) { + const sdk = input.sdk ?? (input.directory ? createSdk(input.directory) : undefined) + if (!sdk) throw new Error("cleanupSession requires sdk or directory") + await waitSessionIdle(sdk, input.sessionID, 5_000).catch(() => undefined) + const current = await status(sdk, input.sessionID).catch(() => undefined) + if (current && current.type !== "idle") { + await sdk.session.abort({ sessionID: input.sessionID }).catch(() => undefined) + await waitSessionIdle(sdk, input.sessionID).catch(() => undefined) + } + await stable(sdk, input.sessionID).catch(() => undefined) + await sdk.session.delete({ sessionID: input.sessionID }).catch(() => undefined) +} + export async function withSession( sdk: ReturnType, title: string, @@ -331,7 +398,7 @@ export async function withSession( try { return await callback(session) } finally { - await sdk.session.delete({ sessionID: session.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: session.id }) } } @@ -444,6 +511,57 @@ export async function seedSessionPermission( return { id: result.id } } +export async function seedSessionTask( + sdk: ReturnType, + input: { + sessionID: string + description: string + prompt: string + subagentType?: string + }, +) { + const text = [ + "Your only valid response is one task tool call.", + `Use this JSON input: ${JSON.stringify({ + description: input.description, + prompt: input.prompt, + subagent_type: input.subagentType ?? "general", + })}`, + "Do not output plain text.", + "Wait for the task to start and return the child session id.", + ].join("\n") + + const result = await seed({ + sdk, + sessionID: input.sessionID, + prompt: text, + timeout: 90_000, + probe: async () => { + const messages = await sdk.session.messages({ sessionID: input.sessionID, limit: 50 }).then((x) => x.data ?? []) + const part = messages + .flatMap((message) => message.parts) + .find((part) => { + if (part.type !== "tool" || part.tool !== "task") return false + if (part.state.input?.description !== input.description) return false + return typeof part.state.metadata?.sessionId === "string" && part.state.metadata.sessionId.length > 0 + }) + + if (!part) return + const id = part.state.metadata?.sessionId + if (typeof id !== "string" || !id) return + const child = await sdk.session + .get({ sessionID: id }) + .then((x) => x.data) + .catch(() => undefined) + if (!child?.id) return + return { sessionID: id } + }, + }) + + if (!result) throw new Error("Timed out seeding task tool") + return result +} + export async function seedSessionTodos( sdk: ReturnType, input: { @@ -518,32 +636,42 @@ export async function openProjectMenu(page: Page, projectSlug: string) { const trigger = page.locator(projectMenuTriggerSelector(projectSlug)).first() await expect(trigger).toHaveCount(1) + const menu = page + .locator(dropdownMenuContentSelector) + .filter({ has: page.locator(projectCloseMenuSelector(projectSlug)) }) + .first() + const close = menu.locator(projectCloseMenuSelector(projectSlug)).first() + + const clicked = await trigger + .click({ timeout: 1500 }) + .then(() => true) + .catch(() => false) + + if (clicked) { + const opened = await menu + .waitFor({ state: "visible", timeout: 1500 }) + .then(() => true) + .catch(() => false) + if (opened) { + await expect(close).toBeVisible() + return menu + } + } + await trigger.focus() await page.keyboard.press("Enter") - const menu = page.locator(dropdownMenuContentSelector).first() const opened = await menu .waitFor({ state: "visible", timeout: 1500 }) .then(() => true) .catch(() => false) if (opened) { - const viewport = page.viewportSize() - const x = viewport ? Math.max(viewport.width - 5, 0) : 1200 - const y = viewport ? Math.max(viewport.height - 5, 0) : 800 - await page.mouse.move(x, y) + await expect(close).toBeVisible() return menu } - await trigger.click({ force: true }) - - await expect(menu).toBeVisible() - - const viewport = page.viewportSize() - const x = viewport ? Math.max(viewport.width - 5, 0) : 1200 - const y = viewport ? Math.max(viewport.height - 5, 0) : 800 - await page.mouse.move(x, y) - return menu + throw new Error(`Failed to open project menu: ${projectSlug}`) } export async function setWorkspacesEnabled(page: Page, projectSlug: string, enabled: boolean) { @@ -556,12 +684,18 @@ export async function setWorkspacesEnabled(page: Page, projectSlug: string, enab if (current === enabled) return - await openProjectMenu(page, projectSlug) + const flip = async (timeout?: number) => { + const menu = await openProjectMenu(page, projectSlug) + const toggle = menu.locator(projectWorkspacesToggleSelector(projectSlug)).first() + await expect(toggle).toBeVisible() + return toggle.click({ force: true, timeout }) + } - const toggle = page.locator(projectWorkspacesToggleSelector(projectSlug)).first() - await expect(toggle).toBeVisible() - await page.waitForTimeout(100) // kilocode_change - wait before toggle click - await toggle.click({ force: true }) + const flipped = await flip(1500) + .then(() => true) + .catch(() => false) + + if (!flipped) await flip() const expected = enabled ? "New workspace" : "New session" await expect(page.getByRole("button", { name: expected }).first()).toBeVisible() diff --git a/packages/app/e2e/app/home.spec.ts b/packages/app/e2e/app/home.spec.ts index f21dc40ec21..a3cedf7cb6f 100644 --- a/packages/app/e2e/app/home.spec.ts +++ b/packages/app/e2e/app/home.spec.ts @@ -1,17 +1,17 @@ import { test, expect } from "../fixtures" -import { serverName } from "../utils" +import { serverNamePattern } from "../utils" test("home renders and shows core entrypoints", async ({ page }) => { await page.goto("/") await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible() - await expect(page.getByRole("button", { name: serverName })).toBeVisible() + await expect(page.getByRole("button", { name: serverNamePattern })).toBeVisible() }) test("server picker dialog opens from home", async ({ page }) => { await page.goto("/") - const trigger = page.getByRole("button", { name: serverName }) + const trigger = page.getByRole("button", { name: serverNamePattern }) await expect(trigger).toBeVisible() await trigger.click() diff --git a/packages/app/e2e/app/server-default.spec.ts b/packages/app/e2e/app/server-default.spec.ts index adbc83473be..2c63130f670 100644 --- a/packages/app/e2e/app/server-default.spec.ts +++ b/packages/app/e2e/app/server-default.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "../fixtures" -import { serverName, serverUrl } from "../utils" -import { clickListItem, closeDialog, clickMenuItem } from "../actions" +import { serverNamePattern, serverUrls } from "../utils" +import { closeDialog, clickMenuItem } from "../actions" const DEFAULT_SERVER_URL_KEY = "opencode.settings.dat:defaultServerUrl" @@ -31,10 +31,9 @@ test("can set a default server on web", async ({ page, gotoSession }) => { const dialog = page.getByRole("dialog") await expect(dialog).toBeVisible() - const row = dialog.locator('[data-slot="list-item"]').filter({ hasText: serverName }).first() - await expect(row).toBeVisible() + await expect(dialog.getByText(serverNamePattern).first()).toBeVisible() - const menuTrigger = row.locator('[data-slot="dropdown-menu-trigger"]').first() + const menuTrigger = dialog.locator('[data-slot="dropdown-menu-trigger"]').first() await expect(menuTrigger).toBeVisible() await menuTrigger.click({ force: true }) @@ -42,14 +41,18 @@ test("can set a default server on web", async ({ page, gotoSession }) => { await expect(menu).toBeVisible() await clickMenuItem(menu, /set as default/i) - await expect.poll(() => page.evaluate((key) => localStorage.getItem(key), DEFAULT_SERVER_URL_KEY)).toBe(serverUrl) - await expect(row.getByText("Default", { exact: true })).toBeVisible() + await expect + .poll(async () => + serverUrls.includes((await page.evaluate((key) => localStorage.getItem(key), DEFAULT_SERVER_URL_KEY)) ?? ""), + ) + .toBe(true) + await expect(dialog.getByText("Default", { exact: true })).toBeVisible() await closeDialog(page, dialog) await ensurePopoverOpen() - const serverRow = popover.locator("button").filter({ hasText: serverName }).first() + const serverRow = popover.locator("button").filter({ hasText: serverNamePattern }).first() await expect(serverRow).toBeVisible() await expect(serverRow.getByText("Default", { exact: true })).toBeVisible() }) diff --git a/packages/app/e2e/app/titlebar-history.spec.ts b/packages/app/e2e/app/titlebar-history.spec.ts index 9d6091176ec..a4592ff1dbc 100644 --- a/packages/app/e2e/app/titlebar-history.spec.ts +++ b/packages/app/e2e/app/titlebar-history.spec.ts @@ -16,7 +16,6 @@ test("titlebar back/forward navigates between sessions", async ({ page, slug, sd const link = page.locator(`[data-session-id="${two.id}"] a`).first() await expect(link).toBeVisible() - await link.scrollIntoViewIfNeeded() await link.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${two.id}(?:\\?|#|$)`)) @@ -56,7 +55,6 @@ test("titlebar forward is cleared after branching history from sidebar", async ( const second = page.locator(`[data-session-id="${b.id}"] a`).first() await expect(second).toBeVisible() - await second.scrollIntoViewIfNeeded() await second.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${b.id}(?:\\?|#|$)`)) @@ -76,7 +74,6 @@ test("titlebar forward is cleared after branching history from sidebar", async ( const third = page.locator(`[data-session-id="${c.id}"] a`).first() await expect(third).toBeVisible() - await third.scrollIntoViewIfNeeded() await third.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${c.id}(?:\\?|#|$)`)) @@ -102,7 +99,6 @@ test("keyboard shortcuts navigate titlebar history", async ({ page, slug, sdk, g const link = page.locator(`[data-session-id="${two.id}"] a`).first() await expect(link).toBeVisible() - await link.scrollIntoViewIfNeeded() await link.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${two.id}(?:\\?|#|$)`)) diff --git a/packages/app/e2e/commands/panels.spec.ts b/packages/app/e2e/commands/panels.spec.ts index 58c1f0a9af3..7e5d7bd6e7a 100644 --- a/packages/app/e2e/commands/panels.spec.ts +++ b/packages/app/e2e/commands/panels.spec.ts @@ -10,6 +10,8 @@ const expanded = async (el: { getAttribute: (name: string) => Promise { await gotoSession() + const reviewPanel = page.locator("#review-panel") + const treeToggle = page.getByRole("button", { name: "Toggle file tree" }).first() await expect(treeToggle).toBeVisible() if (await expanded(treeToggle)) await treeToggle.click() @@ -19,13 +21,13 @@ test("review panel can be toggled via keybind", async ({ page, gotoSession }) => await expect(reviewToggle).toBeVisible() if (await expanded(reviewToggle)) await reviewToggle.click() await expect(reviewToggle).toHaveAttribute("aria-expanded", "false") - await expect(page.locator("#review-panel")).toHaveCount(0) + await expect(reviewPanel).toHaveAttribute("aria-hidden", "true") await page.keyboard.press(`${modKey}+Shift+R`) await expect(reviewToggle).toHaveAttribute("aria-expanded", "true") - await expect(page.locator("#review-panel")).toBeVisible() + await expect(reviewPanel).toHaveAttribute("aria-hidden", "false") await page.keyboard.press(`${modKey}+Shift+R`) await expect(reviewToggle).toHaveAttribute("aria-expanded", "false") - await expect(page.locator("#review-panel")).toHaveCount(0) + await expect(reviewPanel).toHaveAttribute("aria-hidden", "true") }) diff --git a/packages/app/e2e/files/file-tree.spec.ts b/packages/app/e2e/files/file-tree.spec.ts index 44efb7f0046..a5872bdf87c 100644 --- a/packages/app/e2e/files/file-tree.spec.ts +++ b/packages/app/e2e/files/file-tree.spec.ts @@ -43,6 +43,13 @@ test("file tree can expand folders and open a file", async ({ page, gotoSession await tab.click() await expect(tab).toHaveAttribute("aria-selected", "true") + await toggle.click() + await expect(toggle).toHaveAttribute("aria-expanded", "false") + + await toggle.click() + await expect(toggle).toHaveAttribute("aria-expanded", "true") + await expect(allTab).toHaveAttribute("aria-selected", "true") + const viewer = page.locator('[data-component="file"][data-mode="text"]').first() await expect(viewer).toBeVisible() await expect(viewer).toContainText("export default function FileTree") diff --git a/packages/app/e2e/files/file-viewer.spec.ts b/packages/app/e2e/files/file-viewer.spec.ts index bee67c7d128..49fe1baa138 100644 --- a/packages/app/e2e/files/file-viewer.spec.ts +++ b/packages/app/e2e/files/file-viewer.spec.ts @@ -101,3 +101,56 @@ test("cmd+f opens text viewer search while prompt is focused", async ({ page, go await expect(findInput).toBeVisible() await expect(findInput).toBeFocused() }) + +test("cmd+f opens text viewer search while prompt is not focused", async ({ page, gotoSession }) => { + await gotoSession() + + await page.locator(promptSelector).click() + await page.keyboard.type("/open") + + const command = page.locator('[data-slash-id="file.open"]').first() + await expect(command).toBeVisible() + await page.keyboard.press("Enter") + + const dialog = page + .getByRole("dialog") + .filter({ has: page.getByPlaceholder(/search files/i) }) + .first() + await expect(dialog).toBeVisible() + + const input = dialog.getByRole("textbox").first() + await input.fill("package.json") + + const items = dialog.locator('[data-slot="list-item"][data-key^="file:"]') + let index = -1 + await expect + .poll( + async () => { + const keys = await items.evaluateAll((nodes) => nodes.map((node) => node.getAttribute("data-key") ?? "")) + index = keys.findIndex((key) => /packages[\\/]+app[\\/]+package\.json$/i.test(key.replace(/^file:/, ""))) + return index >= 0 + }, + { timeout: 30_000 }, + ) + .toBe(true) + + const item = items.nth(index) + await expect(item).toBeVisible() + await item.click() + + await expect(dialog).toHaveCount(0) + + const tab = page.getByRole("tab", { name: "package.json" }) + await expect(tab).toBeVisible() + await tab.click() + + const viewer = page.locator('[data-component="file"][data-mode="text"]').first() + await expect(viewer).toBeVisible() + + await viewer.click() + await page.keyboard.press(`${modKey}+f`) + + const findInput = page.getByPlaceholder("Find") + await expect(findInput).toBeVisible() + await expect(findInput).toBeFocused() +}) diff --git a/packages/app/e2e/fixtures.ts b/packages/app/e2e/fixtures.ts index e990434fdc9..bc597590227 100644 --- a/packages/app/e2e/fixtures.ts +++ b/packages/app/e2e/fixtures.ts @@ -1,5 +1,5 @@ import { test as base, expect, type Page } from "@playwright/test" -import { cleanupTestProject, createTestProject, seedProjects } from "./actions" +import { cleanupSession, cleanupTestProject, createTestProject, seedProjects, sessionIDFromUrl } from "./actions" import { promptSelector } from "./selectors" import { createSdk, dirSlug, getWorktree, sessionPath } from "./utils" @@ -13,6 +13,8 @@ type TestFixtures = { directory: string slug: string gotoSession: (sessionID?: string) => Promise + trackSession: (sessionID: string, directory?: string) => void + trackDirectory: (directory: string) => void }) => Promise, options?: { extra?: string[] }, ) => Promise @@ -51,20 +53,36 @@ export const test = base.extend({ }, withProject: async ({ page }, use) => { await use(async (callback, options) => { - const directory = await createTestProject() - const slug = dirSlug(directory) - await seedStorage(page, { directory, extra: options?.extra }) + const root = await createTestProject() + const slug = dirSlug(root) + const sessions = new Map() + const dirs = new Set() + await seedStorage(page, { directory: root, extra: options?.extra }) const gotoSession = async (sessionID?: string) => { - await page.goto(sessionPath(directory, sessionID)) + await page.goto(sessionPath(root, sessionID)) await expect(page.locator(promptSelector)).toBeVisible() + const current = sessionIDFromUrl(page.url()) + if (current) trackSession(current) + } + + const trackSession = (sessionID: string, directory?: string) => { + sessions.set(sessionID, directory ?? root) + } + + const trackDirectory = (directory: string) => { + if (directory !== root) dirs.add(directory) } try { await gotoSession() - return await callback({ directory, slug, gotoSession }) + return await callback({ directory: root, slug, gotoSession, trackSession, trackDirectory }) } finally { - await cleanupTestProject(directory) + await Promise.allSettled( + Array.from(sessions, ([sessionID, directory]) => cleanupSession({ sessionID, directory })), + ) + await Promise.allSettled(Array.from(dirs, (directory) => cleanupTestProject(directory))) + await cleanupTestProject(root) } }) }, diff --git a/packages/app/e2e/projects/project-edit.spec.ts b/packages/app/e2e/projects/project-edit.spec.ts index ce4d85b0987..585cb0ac8a6 100644 --- a/packages/app/e2e/projects/project-edit.spec.ts +++ b/packages/app/e2e/projects/project-edit.spec.ts @@ -1,29 +1,16 @@ import { test, expect } from "../fixtures" -import { openSidebar } from "../actions" +import { clickMenuItem, openProjectMenu, openSidebar } from "../actions" test("dialog edit project updates name and startup script", async ({ page, withProject }) => { test.skip(process.platform === "win32", "Skipping on Windows due to hover/menu interaction issues") // kilocode_change await page.setViewportSize({ width: 1400, height: 800 }) - await withProject(async () => { + await withProject(async ({ slug }) => { await openSidebar(page) const open = async () => { - const header = page.locator(".group\\/project").first() - await header.hover() - await page.waitForTimeout(200) // kilocode_change - wait for hover state - const trigger = header.getByRole("button", { name: "More options" }).first() - await expect(trigger).toBeVisible() - await page.waitForTimeout(100) // kilocode_change - wait before trigger click - await trigger.click({ force: true }) - - const menu = page.locator('[data-component="dropdown-menu-content"]').first() - await expect(menu).toBeVisible() - - const editItem = menu.getByRole("menuitem", { name: "Edit" }).first() - await expect(editItem).toBeVisible() - await page.waitForTimeout(100) // kilocode_change - wait before edit item click - await editItem.click({ force: true }) + const menu = await openProjectMenu(page, slug) + await clickMenuItem(menu, /^Edit$/i, { force: true }) const dialog = page.getByRole("dialog") await expect(dialog).toBeVisible() diff --git a/packages/app/e2e/projects/projects-close.spec.ts b/packages/app/e2e/projects/projects-close.spec.ts index 3319ed51968..98784469780 100644 --- a/packages/app/e2e/projects/projects-close.spec.ts +++ b/packages/app/e2e/projects/projects-close.spec.ts @@ -1,36 +1,8 @@ import { test, expect } from "../fixtures" import { createTestProject, cleanupTestProject, openSidebar, clickMenuItem, openProjectMenu } from "../actions" -import { projectCloseHoverSelector, projectSwitchSelector } from "../selectors" +import { projectSwitchSelector } from "../selectors" import { dirSlug } from "../utils" -test("can close a project via hover card close button", async ({ page, withProject }) => { - await page.setViewportSize({ width: 1400, height: 800 }) - - const other = await createTestProject() - const otherSlug = dirSlug(other) - - try { - await withProject( - async () => { - await openSidebar(page) - - const otherButton = page.locator(projectSwitchSelector(otherSlug)).first() - await expect(otherButton).toBeVisible() - await otherButton.hover() - - const close = page.locator(projectCloseHoverSelector(otherSlug)).first() - await expect(close).toBeVisible() - await close.click() - - await expect(otherButton).toHaveCount(0) - }, - { extra: [other] }, - ) - } finally { - await cleanupTestProject(other) - } -}) - test("closing active project navigates to another open project", async ({ page, withProject }) => { test.skip(process.platform === "win32", "Skipping on Windows due to workspace interaction issues") // kilocode_change await page.setViewportSize({ width: 1400, height: 800 }) @@ -54,16 +26,26 @@ test("closing active project navigates to another open project", async ({ page, await clickMenuItem(menu, /^Close$/i, { force: true }) await expect - .poll(() => { - const pathname = new URL(page.url()).pathname - if (new RegExp(`^/${slug}/session(?:/[^/]+)?/?$`).test(pathname)) return "project" - if (pathname === "/") return "home" - return "" - }) + .poll( + () => { + const pathname = new URL(page.url()).pathname + if (new RegExp(`^/${slug}/session(?:/[^/]+)?/?$`).test(pathname)) return "project" + if (pathname === "/") return "home" + return "" + }, + { timeout: 15_000 }, + ) .toMatch(/^(project|home)$/) await expect(page).not.toHaveURL(new RegExp(`/${otherSlug}/session(?:[/?#]|$)`)) - await expect(otherButton).toHaveCount(0) + await expect + .poll( + async () => { + return await page.locator(projectSwitchSelector(otherSlug)).count() + }, + { timeout: 15_000 }, + ) + .toBe(0) }, { extra: [other] }, ) diff --git a/packages/app/e2e/projects/projects-switch.spec.ts b/packages/app/e2e/projects/projects-switch.spec.ts index 27186c9961a..1ff83d5d3d8 100644 --- a/packages/app/e2e/projects/projects-switch.spec.ts +++ b/packages/app/e2e/projects/projects-switch.spec.ts @@ -1,18 +1,39 @@ import { base64Decode } from "@opencode-ai/util/encode" +import type { Page } from "@playwright/test" import { test, expect } from "../fixtures" -import { - defocus, - createTestProject, - cleanupTestProject, - openSidebar, - setWorkspacesEnabled, - sessionIDFromUrl, -} from "../actions" +import { defocus, createTestProject, cleanupTestProject, openSidebar, sessionIDFromUrl, waitSlug } from "../actions" import { projectSwitchSelector, promptSelector, workspaceItemSelector, workspaceNewSessionSelector } from "../selectors" -import { createSdk, dirSlug, sessionPath } from "../utils" +import { dirSlug, resolveDirectory } from "../utils" -function slugFromUrl(url: string) { - return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" +async function workspaces(page: Page, directory: string, enabled: boolean) { + await page.evaluate( + ({ directory, enabled }: { directory: string; enabled: boolean }) => { + const key = "opencode.global.dat:layout" + const raw = localStorage.getItem(key) + const data = raw ? JSON.parse(raw) : {} + const sidebar = data.sidebar && typeof data.sidebar === "object" ? data.sidebar : {} + const current = + sidebar.workspaces && typeof sidebar.workspaces === "object" && !Array.isArray(sidebar.workspaces) + ? sidebar.workspaces + : {} + const next = { ...current } + + if (enabled) next[directory] = true + if (!enabled) delete next[directory] + + localStorage.setItem( + key, + JSON.stringify({ + ...data, + sidebar: { + ...sidebar, + workspaces: next, + }, + }), + ) + }, + { directory, enabled }, + ) } test("can switch between projects from sidebar", async ({ page, withProject }) => { @@ -52,46 +73,39 @@ test("switching back to a project opens the latest workspace session", async ({ const other = await createTestProject() const otherSlug = dirSlug(other) - let rootDir: string | undefined - let workspaceDir: string | undefined - let sessionID: string | undefined - try { await withProject( - async ({ directory, slug }) => { - rootDir = directory + async ({ directory, slug, trackSession, trackDirectory }) => { await defocus(page) + await workspaces(page, directory, true) + await page.reload() + await expect(page.locator(promptSelector)).toBeVisible() await openSidebar(page) - await setWorkspacesEnabled(page, slug, true) + await expect(page.getByRole("button", { name: "New workspace" }).first()).toBeVisible() await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const next = slugFromUrl(page.url()) - if (!next) return "" - if (next === slug) return "" - return next - }, - { timeout: 45_000 }, - ) - .not.toBe("") - - const workspaceSlug = slugFromUrl(page.url()) - workspaceDir = base64Decode(workspaceSlug) - if (!workspaceDir) throw new Error(`Failed to decode workspace slug: ${workspaceSlug}`) + const raw = await waitSlug(page, [slug]) + const dir = base64Decode(raw) + if (!dir) throw new Error(`Failed to decode workspace slug: ${raw}`) + const space = await resolveDirectory(dir) + const next = dirSlug(space) + trackDirectory(space) await openSidebar(page) - const workspace = page.locator(workspaceItemSelector(workspaceSlug)).first() - await expect(workspace).toBeVisible() - await workspace.hover() + const item = page.locator(`${workspaceItemSelector(next)}, ${workspaceItemSelector(raw)}`).first() + await expect(item).toBeVisible() + await item.hover() - const newSession = page.locator(workspaceNewSessionSelector(workspaceSlug)).first() - await expect(newSession).toBeVisible() - await newSession.click({ force: true }) + const btn = page.locator(`${workspaceNewSessionSelector(next)}, ${workspaceNewSessionSelector(raw)}`).first() + await expect(btn).toBeVisible() + await btn.click({ force: true }) - await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session(?:[/?#]|$)`)) + // A new workspace can be discovered via a transient slug before the route and sidebar + // settle to the canonical workspace path on Windows, so interact with either and assert + // against the resolved workspace slug. + await waitSlug(page) + await expect(page).toHaveURL(new RegExp(`/${next}/session(?:[/?#]|$)`)) // Create a session by sending a prompt const prompt = page.locator(promptSelector) @@ -104,9 +118,9 @@ test("switching back to a project opens the latest workspace session", async ({ const created = sessionIDFromUrl(page.url()) if (!created) throw new Error(`Failed to get session ID from url: ${page.url()}`) - sessionID = created + trackSession(created, space) - await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session/${created}(?:[/?#]|$)`)) + await expect(page).toHaveURL(new RegExp(`/${next}/session/${created}(?:[/?#]|$)`)) await openSidebar(page) @@ -125,20 +139,6 @@ test("switching back to a project opens the latest workspace session", async ({ { extra: [other] }, ) } finally { - if (sessionID) { - const id = sessionID - const dirs = [rootDir, workspaceDir].filter((x): x is string => !!x) - await Promise.all( - dirs.map((directory) => - createSdk(directory) - .session.delete({ sessionID: id }) - .catch(() => undefined), - ), - ) - } - if (workspaceDir) { - await cleanupTestProject(workspaceDir) - } await cleanupTestProject(other) } }) diff --git a/packages/app/e2e/projects/workspace-new-session.spec.ts b/packages/app/e2e/projects/workspace-new-session.spec.ts index d46e0836a18..d9e8ab77d9e 100644 --- a/packages/app/e2e/projects/workspace-new-session.spec.ts +++ b/packages/app/e2e/projects/workspace-new-session.spec.ts @@ -1,14 +1,10 @@ import { base64Decode } from "@opencode-ai/util/encode" import type { Page } from "@playwright/test" import { test, expect } from "../fixtures" -import { cleanupTestProject, openSidebar, sessionIDFromUrl, setWorkspacesEnabled } from "../actions" +import { openSidebar, sessionIDFromUrl, setWorkspacesEnabled, slugFromUrl, waitSlug } from "../actions" import { promptSelector, workspaceItemSelector, workspaceNewSessionSelector } from "../selectors" import { createSdk } from "../utils" -function slugFromUrl(url: string) { - return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" -} - async function waitWorkspaceReady(page: Page, slug: string) { await openSidebar(page) await expect @@ -31,20 +27,7 @@ async function createWorkspace(page: Page, root: string, seen: string[]) { await openSidebar(page) await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const slug = slugFromUrl(page.url()) - if (!slug) return "" - if (slug === root) return "" - if (seen.includes(slug)) return "" - return slug - }, - { timeout: 45_000 }, - ) - .not.toBe("") - - const slug = slugFromUrl(page.url()) + const slug = await waitSlug(page, [root, ...seen]) const directory = base64Decode(slug) if (!directory) throw new Error(`Failed to decode workspace slug: ${slug}`) return { slug, directory } @@ -60,12 +43,13 @@ async function openWorkspaceNewSession(page: Page, slug: string) { await expect(button).toBeVisible() await button.click({ force: true }) - await expect.poll(() => slugFromUrl(page.url())).toBe(slug) - await expect(page).toHaveURL(new RegExp(`/${slug}/session(?:[/?#]|$)`)) + const next = await waitSlug(page) + await expect(page).toHaveURL(new RegExp(`/${next}/session(?:[/?#]|$)`)) + return next } async function createSessionFromWorkspace(page: Page, slug: string, text: string) { - await openWorkspaceNewSession(page, slug) + const next = await openWorkspaceNewSession(page, slug) const prompt = page.locator(promptSelector) await expect(prompt).toBeVisible() @@ -76,13 +60,13 @@ async function createSessionFromWorkspace(page: Page, slug: string, text: string await expect.poll(async () => ((await prompt.textContent()) ?? "").trim()).toContain(text) await prompt.press("Enter") - await expect.poll(() => slugFromUrl(page.url())).toBe(slug) + await expect.poll(() => slugFromUrl(page.url())).toBe(next) await expect.poll(() => sessionIDFromUrl(page.url()) ?? "", { timeout: 30_000 }).not.toBe("") const sessionID = sessionIDFromUrl(page.url()) if (!sessionID) throw new Error(`Failed to parse session id from url: ${page.url()}`) - await expect(page).toHaveURL(new RegExp(`/${slug}/session/${sessionID}(?:[/?#]|$)`)) - return sessionID + await expect(page).toHaveURL(new RegExp(`/${next}/session/${sessionID}(?:[/?#]|$)`)) + return { sessionID, slug: next } } async function sessionDirectory(directory: string, sessionID: string) { @@ -98,48 +82,29 @@ test("new sessions from sidebar workspace actions stay in selected workspace", a test.skip(process.platform === "win32", "Skipping on Windows due to workspace interaction issues") // kilocode_change await page.setViewportSize({ width: 1400, height: 800 }) - await withProject(async ({ directory, slug: root }) => { - const workspaces = [] as { slug: string; directory: string }[] - const sessions = [] as string[] + await withProject(async ({ directory, slug: root, trackSession, trackDirectory }) => { + await openSidebar(page) + await setWorkspacesEnabled(page, root, true) - try { - await openSidebar(page) - await setWorkspacesEnabled(page, root, true) + const first = await createWorkspace(page, root, []) + trackDirectory(first.directory) + await waitWorkspaceReady(page, first.slug) - const first = await createWorkspace(page, root, []) - workspaces.push(first) - await waitWorkspaceReady(page, first.slug) + const second = await createWorkspace(page, root, [first.slug]) + trackDirectory(second.directory) + await waitWorkspaceReady(page, second.slug) - const second = await createWorkspace(page, root, [first.slug]) - workspaces.push(second) - await waitWorkspaceReady(page, second.slug) + const firstSession = await createSessionFromWorkspace(page, first.slug, `workspace one ${Date.now()}`) + trackSession(firstSession.sessionID, first.directory) - const firstSession = await createSessionFromWorkspace(page, first.slug, `workspace one ${Date.now()}`) - sessions.push(firstSession) + const secondSession = await createSessionFromWorkspace(page, second.slug, `workspace two ${Date.now()}`) + trackSession(secondSession.sessionID, second.directory) - const secondSession = await createSessionFromWorkspace(page, second.slug, `workspace two ${Date.now()}`) - sessions.push(secondSession) + const thirdSession = await createSessionFromWorkspace(page, first.slug, `workspace one again ${Date.now()}`) + trackSession(thirdSession.sessionID, first.directory) - const thirdSession = await createSessionFromWorkspace(page, first.slug, `workspace one again ${Date.now()}`) - sessions.push(thirdSession) - - await expect.poll(() => sessionDirectory(first.directory, firstSession)).toBe(first.directory) - await expect.poll(() => sessionDirectory(second.directory, secondSession)).toBe(second.directory) - await expect.poll(() => sessionDirectory(first.directory, thirdSession)).toBe(first.directory) - } finally { - const dirs = [directory, ...workspaces.map((workspace) => workspace.directory)] - await Promise.all( - sessions.map((sessionID) => - Promise.all( - dirs.map((dir) => - createSdk(dir) - .session.delete({ sessionID }) - .catch(() => undefined), - ), - ), - ), - ) - await Promise.all(workspaces.map((workspace) => cleanupTestProject(workspace.directory))) - } + await expect.poll(() => sessionDirectory(first.directory, firstSession.sessionID)).toBe(first.directory) + await expect.poll(() => sessionDirectory(second.directory, secondSession.sessionID)).toBe(second.directory) + await expect.poll(() => sessionDirectory(first.directory, thirdSession.sessionID)).toBe(first.directory) }) }) diff --git a/packages/app/e2e/projects/workspaces.spec.ts b/packages/app/e2e/projects/workspaces.spec.ts index abb8755a87e..d27836f5a96 100644 --- a/packages/app/e2e/projects/workspaces.spec.ts +++ b/packages/app/e2e/projects/workspaces.spec.ts @@ -14,14 +14,12 @@ import { openSidebar, openWorkspaceMenu, setWorkspacesEnabled, + slugFromUrl, + waitSlug, } from "../actions" import { dropdownMenuContentSelector, inlineInputSelector, workspaceItemSelector } from "../selectors" import { createSdk, dirSlug } from "../utils" -function slugFromUrl(url: string) { - return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" -} - async function setupWorkspaceTest(page: Page, project: { slug: string }) { const rootSlug = project.slug await openSidebar(page) @@ -29,17 +27,7 @@ async function setupWorkspaceTest(page: Page, project: { slug: string }) { await setWorkspacesEnabled(page, rootSlug, true) await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const slug = slugFromUrl(page.url()) - return slug.length > 0 && slug !== rootSlug - }, - { timeout: 45_000 }, - ) - .toBe(true) - - const slug = slugFromUrl(page.url()) + const slug = await waitSlug(page, [rootSlug]) const dir = base64Decode(slug) await openSidebar(page) @@ -95,18 +83,7 @@ test.skip("can create a workspace", async ({ page, withProject }) => { await expect(page.getByRole("button", { name: "New workspace" }).first()).toBeVisible() await page.getByRole("button", { name: "New workspace" }).first().click() - - await expect - .poll( - () => { - const currentSlug = slugFromUrl(page.url()) - return currentSlug.length > 0 && currentSlug !== slug - }, - { timeout: 45_000 }, - ) - .toBe(true) - - const workspaceSlug = slugFromUrl(page.url()) + const workspaceSlug = await waitSlug(page, [slug]) const workspaceDir = base64Decode(workspaceSlug) await openSidebar(page) @@ -290,7 +267,7 @@ test.skip("can delete a workspace", async ({ page, withProject }) => { await clickMenuItem(menu, /^Delete$/i, { force: true }) await confirmDialog(page, /^Delete workspace$/i) - await expect(page).toHaveURL(new RegExp(`/${rootSlug}/session`)) + await expect.poll(() => base64Decode(slugFromUrl(page.url()))).toBe(project.directory) await expect .poll( @@ -349,9 +326,6 @@ test.skip("can reorder workspaces by drag and drop", async ({ page, withProject const src = page.locator(workspaceItemSelector(from)).first() const dst = page.locator(workspaceItemSelector(to)).first() - await src.scrollIntoViewIfNeeded() - await dst.scrollIntoViewIfNeeded() - const a = await src.boundingBox() const b = await dst.boundingBox() if (!a || !b) throw new Error("Failed to resolve workspace drag bounds") @@ -370,17 +344,7 @@ test.skip("can reorder workspaces by drag and drop", async ({ page, withProject for (const _ of [0, 1]) { const prev = slugFromUrl(page.url()) await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const slug = slugFromUrl(page.url()) - return slug.length > 0 && slug !== rootSlug && slug !== prev - }, - { timeout: 45_000 }, - ) - .toBe(true) - - const slug = slugFromUrl(page.url()) + const slug = await waitSlug(page, [rootSlug, prev]) const dir = base64Decode(slug) workspaces.push({ slug, directory: dir }) diff --git a/packages/app/e2e/prompt/prompt-async.spec.ts b/packages/app/e2e/prompt/prompt-async.spec.ts index ce9b1a7a3bb..51fbc3e4ae3 100644 --- a/packages/app/e2e/prompt/prompt-async.spec.ts +++ b/packages/app/e2e/prompt/prompt-async.spec.ts @@ -1,6 +1,8 @@ import { test, expect } from "../fixtures" import { promptSelector } from "../selectors" -import { sessionIDFromUrl } from "../actions" +import { cleanupSession, sessionIDFromUrl, withSession } from "../actions" + +const text = (value: string | null) => (value ?? "").replace(/\u200B/g, "").trim() // Regression test for Issue #12453: the synchronous POST /message endpoint holds // the connection open while the agent works, causing "Failed to fetch" over @@ -38,6 +40,37 @@ test("prompt succeeds when sync message endpoint is unreachable", async ({ page, ) .toContain(token) } finally { - await sdk.session.delete({ sessionID }).catch(() => undefined) + await cleanupSession({ sdk, sessionID }) } }) + +test("failed prompt send restores the composer input", async ({ page, sdk, gotoSession }) => { + await withSession(sdk, `e2e prompt failure ${Date.now()}`, async (session) => { + const prompt = page.locator(promptSelector) + const value = `restore ${Date.now()}` + + await page.route(`**/session/${session.id}/prompt_async`, (route) => + route.fulfill({ + status: 500, + contentType: "application/json", + body: JSON.stringify({ message: "e2e prompt failure" }), + }), + ) + + await gotoSession(session.id) + await prompt.click() + await page.keyboard.type(value) + await page.keyboard.press("Enter") + + await expect.poll(async () => text(await prompt.textContent())).toBe(value) + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID: session.id, limit: 50 }).then((r) => r.data ?? []) + return messages.length + }, + { timeout: 15_000 }, + ) + .toBe(0) + }) +}) diff --git a/packages/app/e2e/prompt/prompt-history.spec.ts b/packages/app/e2e/prompt/prompt-history.spec.ts new file mode 100644 index 00000000000..36f83da80e6 --- /dev/null +++ b/packages/app/e2e/prompt/prompt-history.spec.ts @@ -0,0 +1,181 @@ +import type { ToolPart } from "@kilocode/sdk/v2/client" +import type { Page } from "@playwright/test" +import { test, expect } from "../fixtures" +import { withSession } from "../actions" +import { promptSelector } from "../selectors" + +const text = (value: string | null) => (value ?? "").replace(/\u200B/g, "").trim() + +const isBash = (part: unknown): part is ToolPart => { + if (!part || typeof part !== "object") return false + if (!("type" in part) || part.type !== "tool") return false + if (!("tool" in part) || part.tool !== "bash") return false + return "state" in part +} + +async function edge(page: Page, pos: "start" | "end") { + await page.locator(promptSelector).evaluate((el: HTMLDivElement, pos: "start" | "end") => { + const selection = window.getSelection() + if (!selection) return + + const walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT) + const nodes: Text[] = [] + for (let node = walk.nextNode(); node; node = walk.nextNode()) { + nodes.push(node as Text) + } + + if (nodes.length === 0) { + const node = document.createTextNode("") + el.appendChild(node) + nodes.push(node) + } + + const node = pos === "start" ? nodes[0]! : nodes[nodes.length - 1]! + const range = document.createRange() + range.setStart(node, pos === "start" ? 0 : (node.textContent ?? "").length) + range.collapse(true) + selection.removeAllRanges() + selection.addRange(range) + }, pos) +} + +async function wait(page: Page, value: string) { + await expect.poll(async () => text(await page.locator(promptSelector).textContent())).toBe(value) +} + +async function reply(sdk: Parameters[0], sessionID: string, token: string) { + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? []) + return messages + .filter((item) => item.info.role === "assistant") + .flatMap((item) => item.parts) + .filter((item) => item.type === "text") + .map((item) => item.text) + .join("\n") + }, + { timeout: 90_000 }, + ) + .toContain(token) +} + +async function shell(sdk: Parameters[0], sessionID: string, cmd: string, token: string) { + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? []) + const part = messages + .filter((item) => item.info.role === "assistant") + .flatMap((item) => item.parts) + .filter(isBash) + .find((item) => item.state.input?.command === cmd && item.state.status === "completed") + + if (!part || part.state.status !== "completed") return + return typeof part.state.metadata?.output === "string" ? part.state.metadata.output : part.state.output + }, + { timeout: 90_000 }, + ) + .toContain(token) +} + +test("prompt history restores unsent draft with arrow navigation", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + await withSession(sdk, `e2e prompt history ${Date.now()}`, async (session) => { + await gotoSession(session.id) + + const prompt = page.locator(promptSelector) + const firstToken = `E2E_HISTORY_ONE_${Date.now()}` + const secondToken = `E2E_HISTORY_TWO_${Date.now()}` + const first = `Reply with exactly: ${firstToken}` + const second = `Reply with exactly: ${secondToken}` + const draft = `draft ${Date.now()}` + + await prompt.click() + await page.keyboard.type(first) + await page.keyboard.press("Enter") + await wait(page, "") + await reply(sdk, session.id, firstToken) + + await prompt.click() + await page.keyboard.type(second) + await page.keyboard.press("Enter") + await wait(page, "") + await reply(sdk, session.id, secondToken) + + await prompt.click() + await page.keyboard.type(draft) + await wait(page, draft) + + await edge(page, "start") + await page.keyboard.press("ArrowUp") + await wait(page, second) + + await page.keyboard.press("ArrowUp") + await wait(page, first) + + await page.keyboard.press("ArrowDown") + await wait(page, second) + + await page.keyboard.press("ArrowDown") + await wait(page, draft) + }) +}) + +test("shell history stays separate from normal prompt history", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + await withSession(sdk, `e2e shell history ${Date.now()}`, async (session) => { + await gotoSession(session.id) + + const prompt = page.locator(promptSelector) + const firstToken = `E2E_SHELL_ONE_${Date.now()}` + const secondToken = `E2E_SHELL_TWO_${Date.now()}` + const normalToken = `E2E_NORMAL_${Date.now()}` + const first = `echo ${firstToken}` + const second = `echo ${secondToken}` + const normal = `Reply with exactly: ${normalToken}` + + await prompt.click() + await page.keyboard.type("!") + await page.keyboard.type(first) + await page.keyboard.press("Enter") + await wait(page, "") + await shell(sdk, session.id, first, firstToken) + + await prompt.click() + await page.keyboard.type("!") + await page.keyboard.type(second) + await page.keyboard.press("Enter") + await wait(page, "") + await shell(sdk, session.id, second, secondToken) + + await prompt.click() + await page.keyboard.type("!") + await page.keyboard.press("ArrowUp") + await wait(page, second) + + await page.keyboard.press("ArrowUp") + await wait(page, first) + + await page.keyboard.press("ArrowDown") + await wait(page, second) + + await page.keyboard.press("ArrowDown") + await wait(page, "") + + await page.keyboard.press("Escape") + await wait(page, "") + + await prompt.click() + await page.keyboard.type(normal) + await page.keyboard.press("Enter") + await wait(page, "") + await reply(sdk, session.id, normalToken) + + await prompt.click() + await page.keyboard.press("ArrowUp") + await wait(page, normal) + }) +}) diff --git a/packages/app/e2e/prompt/prompt-shell.spec.ts b/packages/app/e2e/prompt/prompt-shell.spec.ts new file mode 100644 index 00000000000..b2d195ed747 --- /dev/null +++ b/packages/app/e2e/prompt/prompt-shell.spec.ts @@ -0,0 +1,62 @@ +import type { ToolPart } from "@kilocode/sdk/v2/client" +import { test, expect } from "../fixtures" +import { sessionIDFromUrl } from "../actions" +import { promptSelector } from "../selectors" +import { createSdk } from "../utils" + +const isBash = (part: unknown): part is ToolPart => { + if (!part || typeof part !== "object") return false + if (!("type" in part) || part.type !== "tool") return false + if (!("tool" in part) || part.tool !== "bash") return false + return "state" in part +} + +test("shell mode runs a command in the project directory", async ({ page, withProject }) => { + test.setTimeout(120_000) + + await withProject(async ({ directory, gotoSession, trackSession }) => { + const sdk = createSdk(directory) + const prompt = page.locator(promptSelector) + const cmd = process.platform === "win32" ? "dir" : "ls" + + await gotoSession() + await prompt.click() + await page.keyboard.type("!") + await expect(prompt).toHaveAttribute("aria-label", /enter shell command/i) + + await page.keyboard.type(cmd) + await page.keyboard.press("Enter") + + await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 }) + + const id = sessionIDFromUrl(page.url()) + if (!id) throw new Error(`Failed to parse session id from url: ${page.url()}`) + trackSession(id, directory) + + await expect + .poll( + async () => { + const list = await sdk.session.messages({ sessionID: id, limit: 50 }).then((x) => x.data ?? []) + const msg = list.findLast( + (item) => item.info.role === "assistant" && "path" in item.info && item.info.path.cwd === directory, + ) + if (!msg) return + + const part = msg.parts + .filter(isBash) + .find((item) => item.state.input?.command === cmd && item.state.status === "completed") + + if (!part || part.state.status !== "completed") return + const output = + typeof part.state.metadata?.output === "string" ? part.state.metadata.output : part.state.output + if (!output.includes("README.md")) return + + return { cwd: directory, output } + }, + { timeout: 90_000 }, + ) + .toEqual(expect.objectContaining({ cwd: directory, output: expect.stringContaining("README.md") })) + + await expect(prompt).toHaveText("") + }) +}) diff --git a/packages/app/e2e/prompt/prompt-slash-share.spec.ts b/packages/app/e2e/prompt/prompt-slash-share.spec.ts new file mode 100644 index 00000000000..1363f79102c --- /dev/null +++ b/packages/app/e2e/prompt/prompt-slash-share.spec.ts @@ -0,0 +1,64 @@ +import { test, expect } from "../fixtures" +import { promptSelector } from "../selectors" +import { withSession } from "../actions" + +const shareDisabled = process.env.KILO_DISABLE_SHARE === "true" || process.env.KILO_DISABLE_SHARE === "1" + +async function seed(sdk: Parameters[0], sessionID: string) { + await sdk.session.promptAsync({ + sessionID, + noReply: true, + parts: [{ type: "text", text: "e2e share seed" }], + }) + + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 1 }).then((r) => r.data ?? []) + return messages.length + }, + { timeout: 30_000 }, + ) + .toBeGreaterThan(0) +} + +test("/share and /unshare update session share state", async ({ page, sdk, gotoSession }) => { + test.skip(shareDisabled, "Share is disabled in this environment (KILO_DISABLE_SHARE).") + + await withSession(sdk, `e2e slash share ${Date.now()}`, async (session) => { + const prompt = page.locator(promptSelector) + + await seed(sdk, session.id) + await gotoSession(session.id) + + await prompt.click() + await page.keyboard.type("/share") + await expect(page.locator('[data-slash-id="session.share"]').first()).toBeVisible() + await page.keyboard.press("Enter") + + await expect + .poll( + async () => { + const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data) + return data?.share?.url || undefined + }, + { timeout: 30_000 }, + ) + .not.toBeUndefined() + + await prompt.click() + await page.keyboard.type("/unshare") + await expect(page.locator('[data-slash-id="session.unshare"]').first()).toBeVisible() + await page.keyboard.press("Enter") + + await expect + .poll( + async () => { + const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data) + return data?.share?.url || undefined + }, + { timeout: 30_000 }, + ) + .toBeUndefined() + }) +}) diff --git a/packages/app/e2e/prompt/prompt.spec.ts b/packages/app/e2e/prompt/prompt.spec.ts index ff9f5daf0d4..0466d0988c8 100644 --- a/packages/app/e2e/prompt/prompt.spec.ts +++ b/packages/app/e2e/prompt/prompt.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "../fixtures" import { promptSelector } from "../selectors" -import { sessionIDFromUrl, withSession } from "../actions" +import { cleanupSession, sessionIDFromUrl, withSession } from "../actions" test("can send a prompt and receive a reply", async ({ page, sdk, gotoSession }) => { test.setTimeout(120_000) @@ -46,7 +46,7 @@ test("can send a prompt and receive a reply", async ({ page, sdk, gotoSession }) .toContain(token) } finally { page.off("pageerror", onPageError) - await sdk.session.delete({ sessionID }).catch(() => undefined) + await cleanupSession({ sdk, sessionID }) } if (pageErrors.length > 0) { diff --git a/packages/app/e2e/selectors.ts b/packages/app/e2e/selectors.ts index 5fad2c06b52..2061a112849 100644 --- a/packages/app/e2e/selectors.ts +++ b/packages/app/e2e/selectors.ts @@ -30,8 +30,6 @@ export const sidebarNavSelector = '[data-component="sidebar-nav-desktop"]' export const projectSwitchSelector = (slug: string) => `${sidebarNavSelector} [data-action="project-switch"][data-project="${slug}"]` -export const projectCloseHoverSelector = (slug: string) => `[data-action="project-close-hover"][data-project="${slug}"]` - export const projectMenuTriggerSelector = (slug: string) => `${sidebarNavSelector} [data-action="project-menu"][data-project="${slug}"]` diff --git a/packages/app/e2e/session/session-child-navigation.spec.ts b/packages/app/e2e/session/session-child-navigation.spec.ts new file mode 100644 index 00000000000..ac2dca33c80 --- /dev/null +++ b/packages/app/e2e/session/session-child-navigation.spec.ts @@ -0,0 +1,37 @@ +import { seedSessionTask, withSession } from "../actions" +import { test, expect } from "../fixtures" + +test("task tool child-session link does not trigger stale show errors", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + const errs: string[] = [] + const onError = (err: Error) => { + errs.push(err.message) + } + page.on("pageerror", onError) + + await withSession(sdk, `e2e child nav ${Date.now()}`, async (session) => { + const child = await seedSessionTask(sdk, { + sessionID: session.id, + description: "Open child session", + prompt: "Search the repository for AssistantParts and then reply with exactly CHILD_OK.", + }) + + try { + await gotoSession(session.id) + + const link = page + .locator("a.subagent-link") + .filter({ hasText: /open child session/i }) + .first() + await expect(link).toBeVisible({ timeout: 30_000 }) + await link.click() + + await expect(page).toHaveURL(new RegExp(`/session/${child.sessionID}(?:[/?#]|$)`), { timeout: 30_000 }) + await page.waitForTimeout(1000) + expect(errs).toEqual([]) + } finally { + page.off("pageerror", onError) + } + }) +}) diff --git a/packages/app/e2e/session/session-composer-dock.spec.ts b/packages/app/e2e/session/session-composer-dock.spec.ts index 480c5159ca2..aa39826b714 100644 --- a/packages/app/e2e/session/session-composer-dock.spec.ts +++ b/packages/app/e2e/session/session-composer-dock.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from "../fixtures" -import { clearSessionDockSeed, seedSessionQuestion, seedSessionTodos } from "../actions" +import { cleanupSession, clearSessionDockSeed, seedSessionQuestion, seedSessionTodos } from "../actions" import { permissionDockSelector, promptSelector, @@ -26,7 +26,7 @@ async function withDockSession( try { return await fn(session) } finally { - await sdk.session.delete({ sessionID: session.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: session.id }) } } @@ -315,7 +315,7 @@ test("child session question request blocks parent dock and unblocks after submi await expect(page.locator(promptSelector)).toBeVisible() }) } finally { - await sdk.session.delete({ sessionID: child.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: child.id }) } }) }) @@ -362,7 +362,7 @@ test("child session permission request blocks parent dock and supports allow onc }, ) } finally { - await sdk.session.delete({ sessionID: child.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: child.id }) } }) }) diff --git a/packages/app/e2e/session/session-undo-redo.spec.ts b/packages/app/e2e/session/session-undo-redo.spec.ts index d5e7638fbf4..17de59f79bb 100644 --- a/packages/app/e2e/session/session-undo-redo.spec.ts +++ b/packages/app/e2e/session/session-undo-redo.spec.ts @@ -45,7 +45,7 @@ async function seedConversation(input: { .toBe(true) if (!userMessageID) throw new Error("Expected a user message id") - await expect(input.page.locator(`[data-message-id="${userMessageID}"]`).first()).toBeVisible({ timeout: 30_000 }) + await expect(input.page.locator(`[data-message-id="${userMessageID}"]`)).toHaveCount(1, { timeout: 30_000 }) return { prompt, userMessageID } } @@ -125,7 +125,7 @@ test("slash redo clears revert and restores latest state", async ({ page, withPr .toBeUndefined() await expect(seeded.prompt).not.toContainText(token) - await expect(page.locator(`[data-message-id="${seeded.userMessageID}"]`).first()).toBeVisible() + await expect(page.locator(`[data-message-id="${seeded.userMessageID}"]`)).toHaveCount(1) }) }) }) @@ -161,8 +161,8 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro const firstMessage = page.locator(`[data-message-id="${first.userMessageID}"]`) const secondMessage = page.locator(`[data-message-id="${second.userMessageID}"]`) - await expect(firstMessage.first()).toBeVisible() - await expect(secondMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) + await expect(secondMessage).toHaveCount(1) await second.prompt.click() await page.keyboard.press(`${modKey}+A`) @@ -179,7 +179,7 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro }) .toBe(second.userMessageID) - await expect(firstMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) await expect(secondMessage).toHaveCount(0) await second.prompt.click() @@ -213,7 +213,7 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro }) .toBe(second.userMessageID) - await expect(firstMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) await expect(secondMessage).toHaveCount(0) await second.prompt.click() @@ -229,8 +229,8 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro }) .toBeUndefined() - await expect(firstMessage.first()).toBeVisible() - await expect(secondMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) + await expect(secondMessage).toHaveCount(1) }) }) }) diff --git a/packages/app/e2e/settings/settings-keybinds.spec.ts b/packages/app/e2e/settings/settings-keybinds.spec.ts index 5e98bd158a1..e0d590b31af 100644 --- a/packages/app/e2e/settings/settings-keybinds.spec.ts +++ b/packages/app/e2e/settings/settings-keybinds.spec.ts @@ -32,22 +32,19 @@ test("changing sidebar toggle keybind works", async ({ page, gotoSession }) => { await closeDialog(page, dialog) - const main = page.locator("main") - const initialClasses = (await main.getAttribute("class")) ?? "" - const initiallyClosed = initialClasses.includes("xl:border-l") + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() + const initiallyClosed = (await button.getAttribute("aria-expanded")) !== "true" await page.keyboard.press(`${modKey}+Shift+H`) - await page.waitForTimeout(100) + await expect(button).toHaveAttribute("aria-expanded", initiallyClosed ? "true" : "false") - const afterToggleClasses = (await main.getAttribute("class")) ?? "" - const afterToggleClosed = afterToggleClasses.includes("xl:border-l") + const afterToggleClosed = (await button.getAttribute("aria-expanded")) !== "true" expect(afterToggleClosed).toBe(!initiallyClosed) await page.keyboard.press(`${modKey}+Shift+H`) - await page.waitForTimeout(100) + await expect(button).toHaveAttribute("aria-expanded", initiallyClosed ? "false" : "true") - const finalClasses = (await main.getAttribute("class")) ?? "" - const finalClosed = finalClasses.includes("xl:border-l") + const finalClosed = (await button.getAttribute("aria-expanded")) !== "true" expect(finalClosed).toBe(initiallyClosed) }) diff --git a/packages/app/e2e/settings/settings.spec.ts b/packages/app/e2e/settings/settings.spec.ts index c2a8522eb05..f25e91a315e 100644 --- a/packages/app/e2e/settings/settings.spec.ts +++ b/packages/app/e2e/settings/settings.spec.ts @@ -83,16 +83,23 @@ test("changing theme persists in localStorage", async ({ page, gotoSession }) => const select = dialog.locator(settingsThemeSelector) await expect(select).toBeVisible() + const currentThemeId = await page.evaluate(() => { + return document.documentElement.getAttribute("data-theme") + }) + const currentTheme = (await select.locator('[data-slot="select-select-trigger-value"]').textContent())?.trim() ?? "" + await select.locator('[data-slot="select-select-trigger"]').click() const items = page.locator('[data-slot="select-select-item"]') const count = await items.count() expect(count).toBeGreaterThan(1) - const firstTheme = await items.nth(1).locator('[data-slot="select-select-item-label"]').textContent() - expect(firstTheme).toBeTruthy() + const nextTheme = (await items.locator('[data-slot="select-select-item-label"]').allTextContents()) + .map((x) => x.trim()) + .find((x) => x && x !== currentTheme) + expect(nextTheme).toBeTruthy() - await items.nth(1).click() + await items.filter({ hasText: nextTheme! }).first().click() await page.keyboard.press("Escape") @@ -101,7 +108,7 @@ test("changing theme persists in localStorage", async ({ page, gotoSession }) => }) expect(storedThemeId).not.toBeNull() - expect(storedThemeId).not.toBe("oc-1") + expect(storedThemeId).not.toBe(currentThemeId) const dataTheme = await page.evaluate(() => { return document.documentElement.getAttribute("data-theme") @@ -109,6 +116,42 @@ test("changing theme persists in localStorage", async ({ page, gotoSession }) => expect(dataTheme).toBe(storedThemeId) }) +test("legacy oc-1 theme migrates to oc-2", async ({ page, gotoSession }) => { + await page.addInitScript(() => { + localStorage.setItem("opencode-theme-id", "oc-1") + localStorage.setItem("opencode-theme-css-light", "--background-base:#fff;") + localStorage.setItem("opencode-theme-css-dark", "--background-base:#000;") + }) + + await gotoSession() + + await expect(page.locator("html")).toHaveAttribute("data-theme", "oc-2") + + await expect + .poll(async () => { + return await page.evaluate(() => { + return localStorage.getItem("opencode-theme-id") + }) + }) + .toBe("oc-2") + + await expect + .poll(async () => { + return await page.evaluate(() => { + return localStorage.getItem("opencode-theme-css-light") + }) + }) + .toBeNull() + + await expect + .poll(async () => { + return await page.evaluate(() => { + return localStorage.getItem("opencode-theme-css-dark") + }) + }) + .toBeNull() +}) + test("changing font persists in localStorage and updates CSS variable", async ({ page, gotoSession }) => { await gotoSession() diff --git a/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts b/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts index e37f94f3a7a..d10fca0e490 100644 --- a/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts +++ b/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "../fixtures" -import { closeSidebar, hoverSessionItem } from "../actions" -import { projectSwitchSelector, sessionItemSelector } from "../selectors" +import { cleanupSession, closeSidebar, hoverSessionItem } from "../actions" +import { projectSwitchSelector } from "../selectors" test("collapsed sidebar popover stays open when archiving a session", async ({ page, slug, sdk, gotoSession }) => { const stamp = Date.now() @@ -15,12 +15,15 @@ test("collapsed sidebar popover stays open when archiving a session", async ({ p await gotoSession(one.id) await closeSidebar(page) + const oneItem = page.locator(`[data-session-id="${one.id}"]`).last() + const twoItem = page.locator(`[data-session-id="${two.id}"]`).last() + const project = page.locator(projectSwitchSelector(slug)).first() await expect(project).toBeVisible() await project.hover() - await expect(page.locator(sessionItemSelector(one.id)).first()).toBeVisible() - await expect(page.locator(sessionItemSelector(two.id)).first()).toBeVisible() + await expect(oneItem).toBeVisible() + await expect(twoItem).toBeVisible() const item = await hoverSessionItem(page, one.id) await item @@ -28,9 +31,9 @@ test("collapsed sidebar popover stays open when archiving a session", async ({ p .first() .click() - await expect(page.locator(sessionItemSelector(two.id)).first()).toBeVisible() + await expect(twoItem).toBeVisible() } finally { - await sdk.session.delete({ sessionID: one.id }).catch(() => undefined) - await sdk.session.delete({ sessionID: two.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: one.id }) + await cleanupSession({ sdk, sessionID: two.id }) } }) diff --git a/packages/app/e2e/sidebar/sidebar-session-links.spec.ts b/packages/app/e2e/sidebar/sidebar-session-links.spec.ts index cda2278a950..22f98e94caf 100644 --- a/packages/app/e2e/sidebar/sidebar-session-links.spec.ts +++ b/packages/app/e2e/sidebar/sidebar-session-links.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from "../fixtures" -import { openSidebar, withSession } from "../actions" +import { cleanupSession, openSidebar, withSession } from "../actions" import { promptSelector } from "../selectors" test("sidebar session links navigate to the selected session", async ({ page, slug, sdk, gotoSession }) => { @@ -18,14 +18,13 @@ test("sidebar session links navigate to the selected session", async ({ page, sl const target = page.locator(`[data-session-id="${two.id}"] a`).first() await expect(target).toBeVisible() - await target.scrollIntoViewIfNeeded() await target.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${two.id}(?:\\?|#|$)`)) await expect(page.locator(promptSelector)).toBeVisible() await expect(page.locator(`[data-session-id="${two.id}"] a`).first()).toHaveClass(/\bactive\b/) } finally { - await sdk.session.delete({ sessionID: one.id }).catch(() => undefined) - await sdk.session.delete({ sessionID: two.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: one.id }) + await cleanupSession({ sdk, sessionID: two.id }) } }) diff --git a/packages/app/e2e/sidebar/sidebar.spec.ts b/packages/app/e2e/sidebar/sidebar.spec.ts index 5c78c2220d2..c6bf3fa9ab0 100644 --- a/packages/app/e2e/sidebar/sidebar.spec.ts +++ b/packages/app/e2e/sidebar/sidebar.spec.ts @@ -5,12 +5,14 @@ test("sidebar can be collapsed and expanded", async ({ page, gotoSession }) => { await gotoSession() await openSidebar(page) + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() + await expect(button).toHaveAttribute("aria-expanded", "true") await toggleSidebar(page) - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") await toggleSidebar(page) - await expect(page.locator("main")).not.toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "true") }) test("sidebar collapsed state persists across navigation and reload", async ({ page, sdk, gotoSession }) => { @@ -19,14 +21,15 @@ test("sidebar collapsed state persists across navigation and reload", async ({ p await gotoSession(session1.id) await openSidebar(page) + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() await toggleSidebar(page) - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") await gotoSession(session2.id) - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") await page.reload() - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") const opened = await page.evaluate( () => JSON.parse(localStorage.getItem("opencode.global.dat:layout") ?? "{}").sidebar?.opened, diff --git a/packages/app/e2e/terminal/terminal-tabs.spec.ts b/packages/app/e2e/terminal/terminal-tabs.spec.ts new file mode 100644 index 00000000000..afa6254cd0a --- /dev/null +++ b/packages/app/e2e/terminal/terminal-tabs.spec.ts @@ -0,0 +1,139 @@ +import type { Page } from "@playwright/test" +import { test, expect } from "../fixtures" +import { terminalSelector } from "../selectors" +import { terminalToggleKey, workspacePersistKey } from "../utils" + +type State = { + active?: string + all: Array<{ + id: string + title: string + titleNumber: number + buffer?: string + }> +} + +async function open(page: Page) { + const terminal = page.locator(terminalSelector) + const visible = await terminal.isVisible().catch(() => false) + if (!visible) await page.keyboard.press(terminalToggleKey) + await expect(terminal).toBeVisible() + await expect(terminal.locator("textarea")).toHaveCount(1) +} + +async function run(page: Page, cmd: string) { + const terminal = page.locator(terminalSelector) + await expect(terminal).toBeVisible() + await terminal.click() + await page.keyboard.type(cmd) + await page.keyboard.press("Enter") +} + +async function store(page: Page, key: string) { + return page.evaluate((key) => { + const raw = localStorage.getItem(key) + if (raw) return JSON.parse(raw) as State + + for (let i = 0; i < localStorage.length; i++) { + const next = localStorage.key(i) + if (!next?.endsWith(":workspace:terminal")) continue + const value = localStorage.getItem(next) + if (!value) continue + return JSON.parse(value) as State + } + }, key) +} + +test("inactive terminal tab buffers persist across tab switches", async ({ page, withProject }) => { + await withProject(async ({ directory, gotoSession }) => { + const key = workspacePersistKey(directory, "terminal") + const one = `E2E_TERM_ONE_${Date.now()}` + const two = `E2E_TERM_TWO_${Date.now()}` + const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]') + const first = tabs.filter({ hasText: /Terminal 1/ }).first() + const second = tabs.filter({ hasText: /Terminal 2/ }).first() + + await gotoSession() + await open(page) + + await run(page, `echo ${one}`) + + await page.getByRole("button", { name: /new terminal/i }).click() + await expect(tabs).toHaveCount(2) + + await run(page, `echo ${two}`) + + await first.click() + await expect(first).toHaveAttribute("aria-selected", "true") + await expect + .poll( + async () => { + const state = await store(page, key) + const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? "" + const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? "" + return { + first: first.includes(one), + second: second.includes(two), + } + }, + { timeout: 30_000 }, + ) + .toEqual({ first: false, second: true }) + + await second.click() + await expect(second).toHaveAttribute("aria-selected", "true") + await expect + .poll( + async () => { + const state = await store(page, key) + const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? "" + const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? "" + return { + first: first.includes(one), + second: second.includes(two), + } + }, + { timeout: 30_000 }, + ) + .toEqual({ first: true, second: false }) + }) +}) + +test("closing the active terminal tab falls back to the previous tab", async ({ page, withProject }) => { + await withProject(async ({ directory, gotoSession }) => { + const key = workspacePersistKey(directory, "terminal") + const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]') + + await gotoSession() + await open(page) + + await page.getByRole("button", { name: /new terminal/i }).click() + await expect(tabs).toHaveCount(2) + + const second = tabs.filter({ hasText: /Terminal 2/ }).first() + await second.click() + await expect(second).toHaveAttribute("aria-selected", "true") + + await second.hover() + await page + .getByRole("button", { name: /close terminal/i }) + .nth(1) + .click({ force: true }) + + const first = tabs.filter({ hasText: /Terminal 1/ }).first() + await expect(tabs).toHaveCount(1) + await expect(first).toHaveAttribute("aria-selected", "true") + await expect + .poll( + async () => { + const state = await store(page, key) + return { + count: state?.all.length ?? 0, + first: state?.all.some((item) => item.titleNumber === 1) ?? false, + } + }, + { timeout: 15_000 }, + ) + .toEqual({ count: 1, first: true }) + }) +}) diff --git a/packages/app/e2e/utils.ts b/packages/app/e2e/utils.ts index 42fd9a2c4ae..a0a57e2c207 100644 --- a/packages/app/e2e/utils.ts +++ b/packages/app/e2e/utils.ts @@ -1,5 +1,5 @@ import { createKiloClient } from "@kilocode/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode, checksum } from "@opencode-ai/util/encode" export const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1" export const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" @@ -7,6 +7,22 @@ export const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" export const serverUrl = `http://${serverHost}:${serverPort}` export const serverName = `${serverHost}:${serverPort}` +const localHosts = ["127.0.0.1", "localhost"] + +const serverLabels = (() => { + const url = new URL(serverUrl) + if (!localHosts.includes(url.hostname)) return [serverName] + return localHosts.map((host) => `${host}:${url.port}`) +})() + +export const serverNames = [...new Set(serverLabels)] + +export const serverUrls = serverNames.map((name) => `http://${name}`) + +const escape = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + +export const serverNamePattern = new RegExp(`(?:${serverNames.map(escape).join("|")})`) + export const modKey = process.platform === "darwin" ? "Meta" : "Control" export const terminalToggleKey = "Control+Backquote" @@ -14,6 +30,12 @@ export function createSdk(directory?: string) { return createKiloClient({ baseUrl: serverUrl, directory, throwOnError: true }) } +export async function resolveDirectory(directory: string) { + return createSdk(directory) + .path.get() + .then((x) => x.data?.directory ?? directory) +} + export async function getWorktree() { const sdk = createSdk() const result = await sdk.path.get() @@ -33,3 +55,9 @@ export function dirPath(directory: string) { export function sessionPath(directory: string, sessionID?: string) { return `${dirPath(directory)}/session${sessionID ? `/${sessionID}` : ""}` } + +export function workspacePersistKey(directory: string, key: string) { + const head = (directory.slice(0, 12) || "workspace").replace(/[^a-zA-Z0-9._-]/g, "-") + const sum = checksum(directory) ?? "0" + return `opencode.workspace.${head}.${sum}.dat:workspace:${key}` +} diff --git a/packages/app/package.json b/packages/app/package.json index 24c97f05b11..9d0b6e9b88a 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "7.0.47", + "version": "7.1.3", "description": "", "type": "module", "exports": { @@ -57,7 +57,7 @@ "@thisbeyond/solid-dnd": "0.7.5", "diff": "catalog:", "fuzzysort": "catalog:", - "ghostty-web": "0.4.0", + "ghostty-web": "github:anomalyco/ghostty-web#main", "luxon": "catalog:", "marked": "catalog:", "marked-shiki": "catalog:", diff --git a/packages/app/public/oc-theme-preload.js b/packages/app/public/oc-theme-preload.js index f8c71049619..36fa5d726af 100644 --- a/packages/app/public/oc-theme-preload.js +++ b/packages/app/public/oc-theme-preload.js @@ -1,6 +1,13 @@ ;(function () { - var themeId = localStorage.getItem("opencode-theme-id") - if (!themeId) return + var key = "opencode-theme-id" + var themeId = localStorage.getItem(key) || "oc-2" + + if (themeId === "oc-1") { + themeId = "oc-2" + localStorage.setItem(key, themeId) + localStorage.removeItem("opencode-theme-css-light") + localStorage.removeItem("opencode-theme-css-dark") + } var scheme = localStorage.getItem("opencode-color-scheme") || "system" var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches) @@ -9,9 +16,9 @@ document.documentElement.dataset.theme = themeId document.documentElement.dataset.colorScheme = mode - if (themeId === "oc-1") return + if (themeId === "oc-2") return - var css = localStorage.getItem("opencode-theme-css-" + themeId + "-" + mode) + var css = localStorage.getItem("opencode-theme-css-" + mode) if (css) { var style = document.createElement("style") style.id = "oc-theme-preload" diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 9db8d1d28e9..313f5c1b08c 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -244,7 +244,6 @@ export const PromptInput: Component = (props) => { draggingType: "image" | "@mention" | null mode: "normal" | "shell" applyingHistory: boolean - pendingAutoAccept: boolean }>({ popover: null, historyIndex: -1, @@ -253,7 +252,6 @@ export const PromptInput: Component = (props) => { draggingType: null, mode: "normal", applyingHistory: false, - pendingAutoAccept: false, }) const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 }) @@ -306,12 +304,6 @@ export const PromptInput: Component = (props) => { }), ) - createEffect( - on(sessionKey, () => { - setStore("pendingAutoAccept", false) - }), - ) - const historyComments = () => { const byID = new Map(comments.all().map((item) => [`${item.file}\n${item.id}`, item] as const)) return prompt.context.items().flatMap((item) => { @@ -961,7 +953,7 @@ export const PromptInput: Component = (props) => { const variants = createMemo(() => ["default", ...local.model.variant.list()]) const accepting = createMemo(() => { const id = params.id - if (!id) return store.pendingAutoAccept + if (!id) return permission.isAutoAcceptingDirectory(sdk.directory) return permission.isAutoAccepting(id, sdk.directory) }) @@ -1215,9 +1207,9 @@ export const PromptInput: Component = (props) => { aria-multiline="true" aria-label={placeholder()} contenteditable="true" - autocapitalize="off" - autocorrect="off" - spellcheck={false} + autocapitalize={store.mode === "normal" ? "sentences" : "off"} + autocorrect={store.mode === "normal" ? "on" : "off"} + spellcheck={store.mode === "normal"} onInput={handleInput} onPaste={handlePaste} onCompositionStart={() => setComposing(true)} @@ -1340,7 +1332,7 @@ export const PromptInput: Component = (props) => { variant="ghost" onClick={() => { if (!params.id) { - setStore("pendingAutoAccept", (value) => !value) + permission.toggleAutoAcceptDirectory(sdk.directory) return } permission.toggleAutoAccept(params.id, sdk.directory) diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts index 8e6b751e5be..a06fde67c23 100644 --- a/packages/app/src/components/prompt-input/submit.test.ts +++ b/packages/app/src/components/prompt-input/submit.test.ts @@ -6,10 +6,19 @@ let createPromptSubmit: typeof import("./submit").createPromptSubmit const createdClients: string[] = [] const createdSessions: string[] = [] const enabledAutoAccept: Array<{ sessionID: string; directory: string }> = [] +const optimistic: Array<{ + message: { + agent: string + model: { providerID: string; modelID: string } + variant?: string + } +}> = [] const sentShell: string[] = [] const syncedDirectories: string[] = [] +let params: { id?: string } = {} let selected = "/repo/worktree-a" +let variant: string | undefined const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }] @@ -26,6 +35,7 @@ const clientFor = (directory: string) => { return { data: undefined } }, prompt: async () => ({ data: undefined }), + promptAsync: async () => ({ data: undefined }), command: async () => ({ data: undefined }), abort: async () => ({ data: undefined }), }, @@ -40,7 +50,7 @@ beforeAll(async () => { mock.module("@solidjs/router", () => ({ useNavigate: () => () => undefined, - useParams: () => ({}), + useParams: () => params, })) mock.module("@kilocode/sdk/v2/client", () => ({ @@ -62,7 +72,7 @@ beforeAll(async () => { useLocal: () => ({ model: { current: () => ({ id: "model", provider: { id: "provider" } }), - variant: { current: () => undefined }, + variant: { current: () => variant }, }, agent: { current: () => ({ name: "agent" }), @@ -118,7 +128,11 @@ beforeAll(async () => { data: { command: [] }, session: { optimistic: { - add: () => undefined, + add: (value: { + message: { agent: string; model: { providerID: string; modelID: string }; variant?: string } + }) => { + optimistic.push(value) + }, remove: () => undefined, }, }, @@ -155,9 +169,12 @@ beforeEach(() => { createdClients.length = 0 createdSessions.length = 0 enabledAutoAccept.length = 0 + optimistic.length = 0 + params = {} sentShell.length = 0 syncedDirectories.length = 0 selected = "/repo/worktree-a" + variant = undefined }) describe("prompt submit worktree selection", () => { @@ -219,4 +236,39 @@ describe("prompt submit worktree selection", () => { expect(enabledAutoAccept).toEqual([{ sessionID: "session-1", directory: "/repo/worktree-a" }]) }) + + test("includes the selected variant on optimistic prompts", async () => { + params = { id: "session-1" } + variant = "high" + + const submit = createPromptSubmit({ + info: () => ({ id: "session-1" }), + imageAttachments: () => [], + commentCount: () => 0, + autoAccept: () => false, + mode: () => "normal", + working: () => false, + editor: () => undefined, + queueScroll: () => undefined, + promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), + addToHistory: () => undefined, + resetHistoryNavigation: () => undefined, + setMode: () => undefined, + setPopover: () => undefined, + onSubmit: () => undefined, + }) + + const event = { preventDefault: () => undefined } as unknown as Event + + await submit.handleSubmit(event) + + expect(optimistic).toHaveLength(1) + expect(optimistic[0]).toMatchObject({ + message: { + agent: "agent", + model: { providerID: "provider", modelID: "model" }, + variant: "high", + }, + }) + }) }) diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index ed790174674..65919f59dc6 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -16,6 +16,7 @@ import { Identifier } from "@/utils/id" import { Worktree as WorktreeState } from "@/utils/worktree" import { buildRequestParts } from "./build-request-parts" import { setCursorPosition } from "./editor-dom" +import { formatServerError } from "@/utils/server-errors" type PendingPrompt = { abort: AbortController @@ -286,7 +287,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { .catch((err) => { showToast({ title: language.t("prompt.toast.commandSendFailed.title"), - description: errorMessage(err), + description: formatServerError(err, language.t, language.t("common.requestFailed")), }) restoreInput() }) @@ -315,6 +316,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { time: { created: Date.now() }, agent, model, + variant, } const addOptimisticMessage = () => diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx index 47030aa177e..08ae4d3194e 100644 --- a/packages/app/src/components/session-context-usage.tsx +++ b/packages/app/src/components/session-context-usage.tsx @@ -39,7 +39,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { const usd = createMemo( () => - new Intl.NumberFormat(language.locale(), { + new Intl.NumberFormat(language.intl(), { style: "currency", currency: "USD", }), @@ -77,7 +77,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { {(ctx) => ( <>
- {ctx().total.toLocaleString(language.locale())} + {ctx().total.toLocaleString(language.intl())} {language.t("context.usage.tokens")}
diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx index 04d44b3818e..be5118c2eaf 100644 --- a/packages/app/src/components/session/session-context-tab.tsx +++ b/packages/app/src/components/session/session-context-tab.tsx @@ -128,7 +128,7 @@ export function SessionContextTab() { const usd = createMemo( () => - new Intl.NumberFormat(language.locale(), { + new Intl.NumberFormat(language.intl(), { style: "currency", currency: "USD", }), @@ -136,7 +136,7 @@ export function SessionContextTab() { const metrics = createMemo(() => getSessionContextMetrics(messages(), sync.data.provider.all)) const ctx = createMemo(() => metrics().context) - const formatter = createMemo(() => createSessionContextFormatter(language.locale())) + const formatter = createMemo(() => createSessionContextFormatter(language.intl())) const cost = createMemo(() => { return usd().format(metrics().totalCost) @@ -200,7 +200,7 @@ export function SessionContextTab() { const stats = [ { label: "context.stats.session", value: () => info()?.title ?? params.id ?? "—" }, - { label: "context.stats.messages", value: () => counts().all.toLocaleString(language.locale()) }, + { label: "context.stats.messages", value: () => counts().all.toLocaleString(language.intl()) }, { label: "context.stats.provider", value: providerLabel }, { label: "context.stats.model", value: modelLabel }, { label: "context.stats.limit", value: () => formatter().number(ctx()?.limit) }, @@ -213,8 +213,8 @@ export function SessionContextTab() { label: "context.stats.cacheTokens", value: () => `${formatter().number(ctx()?.cacheRead)} / ${formatter().number(ctx()?.cacheWrite)}`, }, - { label: "context.stats.userMessages", value: () => counts().user.toLocaleString(language.locale()) }, - { label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.locale()) }, + { label: "context.stats.userMessages", value: () => counts().user.toLocaleString(language.intl()) }, + { label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.intl()) }, { label: "context.stats.totalCost", value: cost }, { label: "context.stats.sessionCreated", value: () => formatter().time(info()?.time.created) }, { label: "context.stats.lastActivity", value: () => formatter().time(ctx()?.message.time.created) }, @@ -307,7 +307,7 @@ export function SessionContextTab() {
{breakdownLabel(segment.key)}
-
{segment.percent.toLocaleString(language.locale())}%
+
{segment.percent.toLocaleString(language.intl())}%
)} diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index bb4d9812503..9b4551584c6 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -303,7 +303,12 @@ export function SessionHeader() { }) const canOpen = createMemo(() => platform.platform === "desktop" && !!platform.openPath && server.isLocal()) - const current = createMemo(() => options().find((o) => o.id === prefs.app) ?? options()[0]) + const current = createMemo( + () => + options().find((o) => o.id === prefs.app) ?? + options()[0] ?? + ({ id: "finder", label: fileManager().label, icon: fileManager().icon } as const), + ) const opening = createMemo(() => openRequest.app !== undefined) const selectApp = (app: OpenApp) => { diff --git a/packages/app/src/components/session/session-new-view.tsx b/packages/app/src/components/session/session-new-view.tsx index b7a544ba9a9..52251dbb207 100644 --- a/packages/app/src/components/session/session-new-view.tsx +++ b/packages/app/src/components/session/session-new-view.tsx @@ -4,12 +4,12 @@ import { useSync } from "@/context/sync" import { useSDK } from "@/context/sdk" import { useLanguage } from "@/context/language" import { Icon } from "@opencode-ai/ui/icon" +import { Mark } from "@opencode-ai/ui/logo" import { getDirectory, getFilename } from "@opencode-ai/util/path" const MAIN_WORKTREE = "main" const CREATE_WORKTREE = "create" -const ROOT_CLASS = - "size-full flex flex-col justify-end items-start gap-4 flex-[1_0_0] self-stretch max-w-200 mx-auto 2xl:max-w-[1000px] px-6 pb-16" +const ROOT_CLASS = "size-full flex flex-col" interface NewSessionViewProps { worktree: string @@ -50,33 +50,43 @@ export function NewSessionView(props: NewSessionViewProps) { return (
-
{language.t("command.session.new")}
-
- -
- {getDirectory(projectRoot())} - {getFilename(projectRoot())} +
+
+
+
+ +
{language.t("session.new.title")}
+
+
+
+
+ {getDirectory(projectRoot())} + {getFilename(projectRoot())} +
+
+
+ +
+ {label(current())} +
+
+ + {(project) => ( +
+
+ {language.t("session.new.lastModified")}  + + {DateTime.fromMillis(project().time.updated ?? project().time.created) + .setLocale(language.intl()) + .toRelative()} + +
+
+ )} +
+
-
- -
{label(current())}
-
- - {(project) => ( -
- -
- {language.t("session.new.lastModified")}  - - {DateTime.fromMillis(project().time.updated ?? project().time.created) - .setLocale(language.locale()) - .toRelative()} - -
-
- )} -
) } diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index 21db62950dd..a9839758b72 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -17,6 +17,7 @@ type ProviderItem = ReturnType["connected"]>[num const PROVIDER_NOTES = [ { match: (id: string) => id === "opencode", key: "dialog.provider.opencode.note" }, + { match: (id: string) => id === "opencode-go", key: "dialog.provider.opencodeGo.tagline" }, { match: (id: string) => id === "anthropic", key: "dialog.provider.anthropic.note" }, { match: (id: string) => id.startsWith("github-copilot"), key: "dialog.provider.copilot.note" }, { match: (id: string) => id === "openai", key: "dialog.provider.openai.note" }, @@ -181,21 +182,11 @@ export const SettingsProviders: Component = () => {
{item.name} - - - {language.t("dialog.provider.opencode.tagline")} - - {language.t("dialog.provider.tag.recommended")} - <> - - {language.t("dialog.provider.opencodeGo.tagline")} - - {language.t("dialog.provider.tag.recommended")} - + {language.t("dialog.provider.tag.recommended")}
diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index c27d6a977f2..9e5f12ee4c9 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -217,7 +217,7 @@ export const Terminal = (props: TerminalProps) => { const currentTheme = theme.themes()[theme.themeId()] if (!currentTheme) return fallback const variant = mode === "dark" ? currentTheme.dark : currentTheme.light - if (!variant?.seeds) return fallback + if (!variant?.seeds && !variant?.palette) return fallback const resolved = resolveThemeVariant(variant, mode === "dark") const text = resolved["text-stronger"] ?? fallback.foreground const background = resolved["background-stronger"] ?? fallback.background diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index c2b5a1ef449..b45f8115015 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -155,7 +155,7 @@ export function Titlebar() { return (
-
+
{ @@ -228,10 +230,7 @@ function createGlobalSync() { showToast({ variant: "error", title: language.t("toast.session.listFailed.title", { project }), - description: formatServerError(err, { - unknown: language.t("error.chain.unknown"), - invalidConfiguration: language.t("error.server.invalidConfiguration"), - }), + description: formatServerError(err, language.t), }) }) @@ -261,8 +260,7 @@ function createGlobalSync() { setStore: child[1], vcsCache: cache, loadSessions, - unknownError: language.t("error.chain.unknown"), - invalidConfigurationError: language.t("error.server.invalidConfiguration"), + translate: language.t, }) })() @@ -331,8 +329,7 @@ function createGlobalSync() { url: globalSDK.url, }), requestFailedTitle: language.t("common.requestFailed"), - unknownError: language.t("error.chain.unknown"), - invalidConfigurationError: language.t("error.server.invalidConfiguration"), + translate: language.t, formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }), setGlobalStore: setBootStore, }) diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index 7d9251d3e69..2a55aab853e 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -36,8 +36,7 @@ export async function bootstrapGlobal(input: { connectErrorTitle: string connectErrorDescription: string requestFailedTitle: string - unknownError: string - invalidConfigurationError: string + translate: (key: string, vars?: Record) => string formatMoreCount: (count: number) => string setGlobalStore: SetStoreFunction }) { @@ -91,10 +90,7 @@ export async function bootstrapGlobal(input: { const results = await Promise.allSettled(tasks) const errors = results.filter((r): r is PromiseRejectedResult => r.status === "rejected").map((r) => r.reason) if (errors.length) { - const message = formatServerError(errors[0], { - unknown: input.unknownError, - invalidConfiguration: input.invalidConfigurationError, - }) + const message = formatServerError(errors[0], input.translate) const more = errors.length > 1 ? input.formatMoreCount(errors.length - 1) : "" showToast({ variant: "error", @@ -122,8 +118,7 @@ export async function bootstrapDirectory(input: { setStore: SetStoreFunction vcsCache: VcsCache loadSessions: (directory: string) => Promise | void - unknownError: string - invalidConfigurationError: string + translate: (key: string, vars?: Record) => string }) { if (input.store.status !== "complete") input.setStore("status", "loading") @@ -145,10 +140,7 @@ export async function bootstrapDirectory(input: { showToast({ variant: "error", title: `Failed to reload ${project}`, - description: formatServerError(err, { - unknown: input.unknownError, - invalidConfiguration: input.invalidConfigurationError, - }), + description: formatServerError(err, input.translate), }) input.setStore("status", "partial") return diff --git a/packages/app/src/context/global-sync/event-reducer.test.ts b/packages/app/src/context/global-sync/event-reducer.test.ts index c75e987ab4c..c504bc3b2db 100644 --- a/packages/app/src/context/global-sync/event-reducer.test.ts +++ b/packages/app/src/context/global-sync/event-reducer.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test" import type { Message, Part, PermissionRequest, Project, QuestionRequest, Session } from "@kilocode/sdk/v2/client" import { createStore } from "solid-js/store" import type { State } from "./types" -import { applyDirectoryEvent, applyGlobalEvent } from "./event-reducer" +import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./event-reducer" const rootSession = (input: { id: string; parentID?: string; archived?: number }) => ({ @@ -248,6 +248,62 @@ describe("applyDirectoryEvent", () => { } }) + test("cleans caches for trimmed sessions on session.created", () => { + const dropped = rootSession({ id: "ses_b" }) + const kept = rootSession({ id: "ses_a" }) + const message = userMessage("msg_1", dropped.id) + const todos: string[] = [] + const [store, setStore] = createStore( + baseState({ + limit: 1, + session: [dropped], + message: { [dropped.id]: [message] }, + part: { [message.id]: [textPart("prt_1", dropped.id, message.id)] }, + session_diff: { [dropped.id]: [] }, + todo: { [dropped.id]: [] }, + permission: { [dropped.id]: [] }, + question: { [dropped.id]: [] }, + session_status: { [dropped.id]: { type: "busy" } }, + }), + ) + + applyDirectoryEvent({ + event: { type: "session.created", properties: { info: kept } }, + store, + setStore, + push() {}, + directory: "/tmp", + loadLsp() {}, + setSessionTodo(sessionID, value) { + if (value !== undefined) return + todos.push(sessionID) + }, + }) + + expect(store.session.map((x) => x.id)).toEqual([kept.id]) + expect(store.message[dropped.id]).toBeUndefined() + expect(store.part[message.id]).toBeUndefined() + expect(store.session_diff[dropped.id]).toBeUndefined() + expect(store.todo[dropped.id]).toBeUndefined() + expect(store.permission[dropped.id]).toBeUndefined() + expect(store.question[dropped.id]).toBeUndefined() + expect(store.session_status[dropped.id]).toBeUndefined() + expect(todos).toEqual([dropped.id]) + }) + + test("cleanupDroppedSessionCaches clears part-only orphan state", () => { + const [store, setStore] = createStore( + baseState({ + session: [rootSession({ id: "ses_keep" })], + part: { msg_1: [textPart("prt_1", "ses_drop", "msg_1")] }, + }), + ) + + cleanupDroppedSessionCaches(store, setStore, store.session) + + expect(store.part.msg_1).toBeUndefined() + }) + test("upserts and removes messages while clearing orphaned parts", () => { const sessionID = "ses_1" const [store, setStore] = createStore( diff --git a/packages/app/src/context/global-sync/event-reducer.ts b/packages/app/src/context/global-sync/event-reducer.ts index dcba38eeb97..6b5e14ccdef 100644 --- a/packages/app/src/context/global-sync/event-reducer.ts +++ b/packages/app/src/context/global-sync/event-reducer.ts @@ -13,6 +13,7 @@ import type { } from "@kilocode/sdk/v2/client" import type { State, VcsCache } from "./types" import { trimSessions } from "./session-trim" +import { dropSessionCaches } from "./session-cache" export function applyGlobalEvent(input: { event: { type: string; properties?: unknown } @@ -40,37 +41,44 @@ export function applyGlobalEvent(input: { } function cleanupSessionCaches( - store: Store, setStore: SetStoreFunction, sessionID: string, setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, ) { if (!sessionID) return - const hasAny = - store.message[sessionID] !== undefined || - store.session_diff[sessionID] !== undefined || - store.todo[sessionID] !== undefined || - store.permission[sessionID] !== undefined || - store.question[sessionID] !== undefined || - store.session_status[sessionID] !== undefined setSessionTodo?.(sessionID, undefined) - if (!hasAny) return setStore( produce((draft) => { - const messages = draft.message[sessionID] - if (messages) { - for (const message of messages) { - const id = message?.id - if (!id) continue - delete draft.part[id] - } - } - delete draft.message[sessionID] - delete draft.session_diff[sessionID] - delete draft.todo[sessionID] - delete draft.permission[sessionID] - delete draft.question[sessionID] - delete draft.session_status[sessionID] + dropSessionCaches(draft, [sessionID]) + }), + ) +} + +export function cleanupDroppedSessionCaches( + store: Store, + setStore: SetStoreFunction, + next: Session[], + setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, +) { + const keep = new Set(next.map((item) => item.id)) + const stale = [ + ...Object.keys(store.message), + ...Object.keys(store.session_diff), + ...Object.keys(store.todo), + ...Object.keys(store.permission), + ...Object.keys(store.question), + ...Object.keys(store.session_status), + ...Object.values(store.part) + .map((parts) => parts?.find((part) => !!part?.sessionID)?.sessionID) + .filter((sessionID): sessionID is string => !!sessionID), + ].filter((sessionID, index, list) => !keep.has(sessionID) && list.indexOf(sessionID) === index) + if (stale.length === 0) return + for (const sessionID of stale) { + setSessionTodo?.(sessionID, undefined) + } + setStore( + produce((draft) => { + dropSessionCaches(draft, stale) }), ) } @@ -102,6 +110,7 @@ export function applyDirectoryEvent(input: { next.splice(result.index, 0, info) const trimmed = trimSessions(next, { limit: input.store.limit, permission: input.store.permission }) input.setStore("session", reconcile(trimmed, { key: "id" })) + cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) if (!info.parentID) input.setStore("sessionTotal", (value) => value + 1) break } @@ -117,7 +126,7 @@ export function applyDirectoryEvent(input: { }), ) } - cleanupSessionCaches(input.store, input.setStore, info.id, input.setSessionTodo) + cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break @@ -130,6 +139,7 @@ export function applyDirectoryEvent(input: { next.splice(result.index, 0, info) const trimmed = trimSessions(next, { limit: input.store.limit, permission: input.store.permission }) input.setStore("session", reconcile(trimmed, { key: "id" })) + cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) break } case "session.deleted": { @@ -143,7 +153,7 @@ export function applyDirectoryEvent(input: { }), ) } - cleanupSessionCaches(input.store, input.setStore, info.id, input.setSessionTodo) + cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break diff --git a/packages/app/src/context/global-sync/session-cache.test.ts b/packages/app/src/context/global-sync/session-cache.test.ts new file mode 100644 index 00000000000..e58a2e61edc --- /dev/null +++ b/packages/app/src/context/global-sync/session-cache.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, test } from "bun:test" +import type { + FileDiff, + Message, + Part, + PermissionRequest, + QuestionRequest, + SessionStatus, + Todo, +} from "@kilocode/sdk/v2/client" +import { dropSessionCaches, pickSessionCacheEvictions } from "./session-cache" + +const msg = (id: string, sessionID: string) => + ({ + id, + sessionID, + role: "user", + time: { created: 1 }, + agent: "assistant", + model: { providerID: "openai", modelID: "gpt" }, + }) as Message + +const part = (id: string, sessionID: string, messageID: string) => + ({ + id, + sessionID, + messageID, + type: "text", + text: id, + }) as Part + +describe("app session cache", () => { + test("dropSessionCaches clears orphaned parts without message rows", () => { + const store: { + session_status: Record + session_diff: Record + todo: Record + message: Record + part: Record + permission: Record + question: Record + } = { + session_status: { ses_1: { type: "busy" } as SessionStatus }, + session_diff: { ses_1: [] }, + todo: { ses_1: [] as Todo[] }, + message: {}, + part: { msg_1: [part("prt_1", "ses_1", "msg_1")] }, + permission: { ses_1: [] as PermissionRequest[] }, + question: { ses_1: [] as QuestionRequest[] }, + } + + dropSessionCaches(store, ["ses_1"]) + + expect(store.message.ses_1).toBeUndefined() + expect(store.part.msg_1).toBeUndefined() + expect(store.todo.ses_1).toBeUndefined() + expect(store.session_diff.ses_1).toBeUndefined() + expect(store.session_status.ses_1).toBeUndefined() + expect(store.permission.ses_1).toBeUndefined() + expect(store.question.ses_1).toBeUndefined() + }) + + test("dropSessionCaches clears message-backed parts", () => { + const m = msg("msg_1", "ses_1") + const store: { + session_status: Record + session_diff: Record + todo: Record + message: Record + part: Record + permission: Record + question: Record + } = { + session_status: {}, + session_diff: {}, + todo: {}, + message: { ses_1: [m] }, + part: { [m.id]: [part("prt_1", "ses_1", m.id)] }, + permission: {}, + question: {}, + } + + dropSessionCaches(store, ["ses_1"]) + + expect(store.message.ses_1).toBeUndefined() + expect(store.part[m.id]).toBeUndefined() + }) + + test("pickSessionCacheEvictions preserves requested sessions", () => { + const seen = new Set(["ses_1", "ses_2", "ses_3"]) + + const stale = pickSessionCacheEvictions({ + seen, + keep: "ses_4", + limit: 2, + preserve: ["ses_1"], + }) + + expect(stale).toEqual(["ses_2", "ses_3"]) + expect([...seen]).toEqual(["ses_1", "ses_4"]) + }) +}) diff --git a/packages/app/src/context/global-sync/session-cache.ts b/packages/app/src/context/global-sync/session-cache.ts new file mode 100644 index 00000000000..2ffce9cfe4a --- /dev/null +++ b/packages/app/src/context/global-sync/session-cache.ts @@ -0,0 +1,62 @@ +import type { + FileDiff, + Message, + Part, + PermissionRequest, + QuestionRequest, + SessionStatus, + Todo, +} from "@kilocode/sdk/v2/client" + +export const SESSION_CACHE_LIMIT = 40 + +type SessionCache = { + session_status: Record + session_diff: Record + todo: Record + message: Record + part: Record + permission: Record + question: Record +} + +export function dropSessionCaches(store: SessionCache, sessionIDs: Iterable) { + const stale = new Set(Array.from(sessionIDs).filter(Boolean)) + if (stale.size === 0) return + + for (const key of Object.keys(store.part)) { + const parts = store.part[key] + if (!parts?.some((part) => stale.has(part?.sessionID ?? ""))) continue + delete store.part[key] + } + + for (const sessionID of stale) { + delete store.message[sessionID] + delete store.todo[sessionID] + delete store.session_diff[sessionID] + delete store.session_status[sessionID] + delete store.permission[sessionID] + delete store.question[sessionID] + } +} + +export function pickSessionCacheEvictions(input: { + seen: Set + keep: string + limit: number + preserve?: Iterable +}) { + const stale: string[] = [] + const keep = new Set([input.keep, ...Array.from(input.preserve ?? [])]) + if (input.seen.has(input.keep)) input.seen.delete(input.keep) + input.seen.add(input.keep) + for (const id of input.seen) { + if (input.seen.size - stale.length <= input.limit) break + if (keep.has(id)) continue + stale.push(id) + } + for (const id of stale) { + input.seen.delete(id) + } + return stale +} diff --git a/packages/app/src/context/language.tsx b/packages/app/src/context/language.tsx index cae4b835419..9bf9d504c8c 100644 --- a/packages/app/src/context/language.tsx +++ b/packages/app/src/context/language.tsx @@ -19,6 +19,7 @@ import { dict as no } from "@/i18n/no" import { dict as br } from "@/i18n/br" import { dict as th } from "@/i18n/th" import { dict as bs } from "@/i18n/bs" +import { dict as nl } from "@/i18n/nl" import { dict as tr } from "@/i18n/tr" import { dict as uiEn } from "@opencode-ai/ui/i18n/en" import { dict as uiZh } from "@opencode-ai/ui/i18n/zh" @@ -36,6 +37,7 @@ import { dict as uiNo } from "@opencode-ai/ui/i18n/no" import { dict as uiBr } from "@opencode-ai/ui/i18n/br" import { dict as uiTh } from "@opencode-ai/ui/i18n/th" import { dict as uiBs } from "@opencode-ai/ui/i18n/bs" +import { dict as uiNl } from "@opencode-ai/ui/i18n/nl" import { dict as uiTr } from "@opencode-ai/ui/i18n/tr" // kilocode_change start @@ -55,6 +57,7 @@ import { dict as kiloNo } from "@kilocode/kilo-i18n/no" import { dict as kiloBr } from "@kilocode/kilo-i18n/br" import { dict as kiloTh } from "@kilocode/kilo-i18n/th" import { dict as kiloBs } from "@kilocode/kilo-i18n/bs" +import { dict as kiloNl } from "@kilocode/kilo-i18n/nl" import { dict as kiloTr } from "@kilocode/kilo-i18n/tr" // kilocode_change end @@ -75,6 +78,7 @@ export type Locale = | "br" | "th" | "bs" + | "nl" | "tr" type RawDictionary = typeof en & typeof uiEn & typeof kiloEn // kilocode_change @@ -97,6 +101,7 @@ const LOCALES: readonly Locale[] = [ "pl", "ru", "bs", + "nl", "ar", "no", "br", @@ -104,6 +109,28 @@ const LOCALES: readonly Locale[] = [ "tr", ] +const INTL: Record = { + en: "en", + zh: "zh-Hans", + zht: "zh-Hant", + ko: "ko", + de: "de", + es: "es", + fr: "fr", + da: "da", + ja: "ja", + pl: "pl", + ru: "ru", + ar: "ar", + no: "nb-NO", + br: "pt-BR", + th: "th", + bs: "bs", + nl: "nl", + + tr: "tr", +} + const LABEL_KEY: Record = { en: "language.en", zh: "language.zh", @@ -121,6 +148,7 @@ const LABEL_KEY: Record = { br: "language.br", th: "language.th", bs: "language.bs", + nl: "language.nl", tr: "language.tr", } @@ -142,10 +170,12 @@ const DICT: Record = { br: { ...base, ...i18n.flatten({ ...br, ...uiBr, ...kiloBr }) }, th: { ...base, ...i18n.flatten({ ...th, ...uiTh, ...kiloTh }) }, bs: { ...base, ...i18n.flatten({ ...bs, ...uiBs, ...kiloBs }) }, + nl: { ...base, ...i18n.flatten({ ...nl, ...uiNl, ...kiloNl }) }, tr: { ...base, ...i18n.flatten({ ...tr, ...uiTr, ...kiloTr }) }, } const localeMatchers: Array<{ locale: Locale; match: (language: string) => boolean }> = [ + { locale: "en", match: (language) => language.startsWith("en") }, { locale: "zht", match: (language) => language.startsWith("zh") && language.includes("hant") }, { locale: "zh", match: (language) => language.startsWith("zh") }, { locale: "ko", match: (language) => language.startsWith("ko") }, @@ -164,6 +194,7 @@ const localeMatchers: Array<{ locale: Locale; match: (language: string) => boole { locale: "br", match: (language) => language.startsWith("pt") }, { locale: "th", match: (language) => language.startsWith("th") }, { locale: "bs", match: (language) => language.startsWith("bs") }, + { locale: "nl", match: (language) => language.startsWith("nl") }, { locale: "tr", match: (language) => language.startsWith("tr") }, ] @@ -184,6 +215,7 @@ const PARITY_CHECK: Record, Record> = { br, th, bs, + nl, tr, } void PARITY_CHECK @@ -217,6 +249,8 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont ) const locale = createMemo(() => normalizeLocale(store.locale)) + console.log("locale", locale()) + const intl = createMemo(() => INTL[locale()]) const dict = createMemo(() => DICT[locale()]) @@ -233,6 +267,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont return { ready, locale, + intl, locales: LOCALES, label, t, diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx index ac5da60e862..75d1334a5a5 100644 --- a/packages/app/src/context/local.tsx +++ b/packages/app/src/context/local.tsx @@ -35,6 +35,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const agent = (() => { const list = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent" && !x.hidden)) + const models = useModels() + const [store, setStore] = createStore<{ current?: string }>({ @@ -53,11 +55,17 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ setStore("current", undefined) return } - if (name && available.some((x) => x.name === name)) { - setStore("current", name) - return - } - setStore("current", available[0].name) + const match = name ? available.find((x) => x.name === name) : undefined + const value = match ?? available[0] + if (!value) return + setStore("current", value.name) + if (!value.model) return + setModel({ + providerID: value.model.providerID, + modelID: value.model.modelID, + }) + if (value.variant) + models.variant.set({ providerID: value.model.providerID, modelID: value.model.modelID }, value.variant) }, move(direction: 1 | -1) { const available = list() @@ -71,11 +79,13 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const value = available[next] if (!value) return setStore("current", value.name) - if (value.model) - setModel({ - providerID: value.model.providerID, - modelID: value.model.modelID, - }) + if (!value.model) return + setModel({ + providerID: value.model.providerID, + modelID: value.model.modelID, + }) + if (value.variant) + models.variant.set({ providerID: value.model.providerID, modelID: value.model.modelID }, value.variant) }, } })() diff --git a/packages/app/src/context/permission-auto-respond.test.ts b/packages/app/src/context/permission-auto-respond.test.ts index ab60df6e383..547de1c39ae 100644 --- a/packages/app/src/context/permission-auto-respond.test.ts +++ b/packages/app/src/context/permission-auto-respond.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import type { PermissionRequest, Session } from "@kilocode/sdk/v2/client" import { base64Encode } from "@opencode-ai/util/encode" -import { autoRespondsPermission } from "./permission-auto-respond" +import { autoRespondsPermission, isDirectoryAutoAccepting } from "./permission-auto-respond" const session = (input: { id: string; parentID?: string }) => ({ @@ -60,4 +60,43 @@ describe("autoRespondsPermission", () => { expect(autoRespondsPermission(autoAccept, sessions, permission("child"), directory)).toBe(true) }) + + test("falls back to directory-level auto-accept", () => { + const directory = "/tmp/project" + const sessions = [session({ id: "root" })] + const autoAccept = { + [`${base64Encode(directory)}/*`]: true, + } + + expect(autoRespondsPermission(autoAccept, sessions, permission("root"), directory)).toBe(true) + }) + + test("session-level override takes precedence over directory-level", () => { + const directory = "/tmp/project" + const sessions = [session({ id: "root" })] + const autoAccept = { + [`${base64Encode(directory)}/*`]: true, + [`${base64Encode(directory)}/root`]: false, + } + + expect(autoRespondsPermission(autoAccept, sessions, permission("root"), directory)).toBe(false) + }) +}) + +describe("isDirectoryAutoAccepting", () => { + test("returns true when directory key is set", () => { + const directory = "/tmp/project" + const autoAccept = { [`${base64Encode(directory)}/*`]: true } + expect(isDirectoryAutoAccepting(autoAccept, directory)).toBe(true) + }) + + test("returns false when directory key is not set", () => { + expect(isDirectoryAutoAccepting({}, "/tmp/project")).toBe(false) + }) + + test("returns false when directory key is explicitly false", () => { + const directory = "/tmp/project" + const autoAccept = { [`${base64Encode(directory)}/*`]: false } + expect(isDirectoryAutoAccepting(autoAccept, directory)).toBe(false) + }) }) diff --git a/packages/app/src/context/permission-auto-respond.ts b/packages/app/src/context/permission-auto-respond.ts index 727ccc93756..b206deedff9 100644 --- a/packages/app/src/context/permission-auto-respond.ts +++ b/packages/app/src/context/permission-auto-respond.ts @@ -5,9 +5,19 @@ export function acceptKey(sessionID: string, directory?: string) { return `${base64Encode(directory)}/${sessionID}` } +export function directoryAcceptKey(directory: string) { + return `${base64Encode(directory)}/*` +} + function accepted(autoAccept: Record, sessionID: string, directory?: string) { const key = acceptKey(sessionID, directory) - return autoAccept[key] ?? autoAccept[sessionID] + const directoryKey = directory ? directoryAcceptKey(directory) : undefined + return autoAccept[key] ?? autoAccept[sessionID] ?? (directoryKey ? autoAccept[directoryKey] : undefined) +} + +export function isDirectoryAutoAccepting(autoAccept: Record, directory: string) { + const key = directoryAcceptKey(directory) + return autoAccept[key] ?? false } function sessionLineage(session: { id: string; parentID?: string }[], sessionID: string) { diff --git a/packages/app/src/context/permission.tsx b/packages/app/src/context/permission.tsx index bd7ce3ac7a9..6f890da7c96 100644 --- a/packages/app/src/context/permission.tsx +++ b/packages/app/src/context/permission.tsx @@ -1,4 +1,4 @@ -import { createMemo, onCleanup } from "solid-js" +import { createEffect, createMemo, onCleanup } from "solid-js" import { createStore, produce } from "solid-js/store" import { createSimpleContext } from "@opencode-ai/ui/context" import type { PermissionRequest } from "@kilocode/sdk/v2/client" @@ -7,7 +7,12 @@ import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSync } from "./global-sync" import { useParams } from "@solidjs/router" import { decode64 } from "@/utils/base64" -import { acceptKey, autoRespondsPermission } from "./permission-auto-respond" +import { + acceptKey, + directoryAcceptKey, + isDirectoryAutoAccepting, + autoRespondsPermission, +} from "./permission-auto-respond" type PermissionRespondFn = (input: { sessionID: string @@ -76,6 +81,25 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple }), ) + // When config has permission: "allow", auto-enable directory-level auto-accept + createEffect(() => { + if (!ready()) return + const directory = decode64(params.dir) + if (!directory) return + const [childStore] = globalSync.child(directory) + const perm = childStore.config.permission + if (typeof perm === "string" && perm === "allow") { + const key = directoryAcceptKey(directory) + if (store.autoAccept[key] === undefined) { + setStore( + produce((draft) => { + draft.autoAccept[key] = true + }), + ) + } + } + }) + const MAX_RESPONDED = 1000 const RESPONDED_TTL_MS = 60 * 60 * 1000 const responded = new Map() @@ -119,6 +143,10 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple return autoRespondsPermission(store.autoAccept, session, { sessionID }, directory) } + function isAutoAcceptingDirectory(directory: string) { + return isDirectoryAutoAccepting(store.autoAccept, directory) + } + function shouldAutoRespond(permission: PermissionRequest, directory?: string) { const session = directory ? globalSync.child(directory, { bootstrap: false })[0].session : [] return autoRespondsPermission(store.autoAccept, session, permission, directory) @@ -142,6 +170,36 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple }) onCleanup(unsubscribe) + function enableDirectory(directory: string) { + const key = directoryAcceptKey(directory) + setStore( + produce((draft) => { + draft.autoAccept[key] = true + }), + ) + + globalSDK.client.permission + .list({ directory }) + .then((x) => { + if (!isAutoAcceptingDirectory(directory)) return + for (const perm of x.data ?? []) { + if (!perm?.id) continue + if (!shouldAutoRespond(perm, directory)) continue + respondOnce(perm, directory) + } + }) + .catch(() => undefined) + } + + function disableDirectory(directory: string) { + const key = directoryAcceptKey(directory) + setStore( + produce((draft) => { + draft.autoAccept[key] = false + }), + ) + } + function enable(sessionID: string, directory: string) { const key = acceptKey(sessionID, directory) const version = bumpEnableVersion(sessionID, directory) @@ -185,6 +243,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple return shouldAutoRespond(permission, directory) }, isAutoAccepting, + isAutoAcceptingDirectory, toggleAutoAccept(sessionID: string, directory: string) { if (isAutoAccepting(sessionID, directory)) { disable(sessionID, directory) @@ -193,6 +252,13 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple enable(sessionID, directory) }, + toggleAutoAcceptDirectory(directory: string) { + if (isAutoAcceptingDirectory(directory)) { + disableDirectory(directory) + return + } + enableDirectory(directory) + }, enableAutoAccept(sessionID: string, directory: string) { if (isAutoAccepting(sessionID, directory)) return enable(sessionID, directory) @@ -201,6 +267,11 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple disable(sessionID, directory) }, permissionsEnabled, + isPermissionAllowAll(directory: string) { + const [childStore] = globalSync.child(directory) + const perm = childStore.config.permission + return typeof perm === "string" && perm === "allow" + }, } }, }) diff --git a/packages/app/src/context/sync.tsx b/packages/app/src/context/sync.tsx index b4a9c48d0b4..d41622d9a71 100644 --- a/packages/app/src/context/sync.tsx +++ b/packages/app/src/context/sync.tsx @@ -6,6 +6,7 @@ import { createSimpleContext } from "@opencode-ai/ui/context" import { useGlobalSync } from "./global-sync" import { useSDK } from "./sdk" import type { Message, Part } from "@kilocode/sdk/v2/client" +import { SESSION_CACHE_LIMIT, dropSessionCaches, pickSessionCacheEvictions } from "./global-sync/session-cache" function sortParts(parts: Part[]) { return parts.filter((part) => !!part?.id).sort((a, b) => cmp(a.id, b.id)) @@ -108,6 +109,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const inflight = new Map>() const inflightDiff = new Map>() const inflightTodo = new Map>() + const maxDirs = 30 + const seen = new Map>() const [meta, setMeta] = createStore({ limit: {} as Record, complete: {} as Record, @@ -121,6 +124,62 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ return undefined } + const seenFor = (directory: string) => { + const existing = seen.get(directory) + if (existing) { + seen.delete(directory) + seen.set(directory, existing) + return existing + } + const created = new Set() + seen.set(directory, created) + while (seen.size > maxDirs) { + const first = seen.keys().next().value + if (!first) break + const stale = [...(seen.get(first) ?? [])] + seen.delete(first) + const [, setStore] = globalSync.child(first, { bootstrap: false }) + evict(first, setStore, stale) + } + return created + } + + const clearMeta = (directory: string, sessionIDs: string[]) => { + if (sessionIDs.length === 0) return + setMeta( + produce((draft) => { + for (const sessionID of sessionIDs) { + const key = keyFor(directory, sessionID) + delete draft.limit[key] + delete draft.complete[key] + delete draft.loading[key] + } + }), + ) + } + + const evict = (directory: string, setStore: Setter, sessionIDs: string[]) => { + if (sessionIDs.length === 0) return + for (const sessionID of sessionIDs) { + globalSync.todo.set(sessionID, undefined) + } + setStore( + produce((draft) => { + dropSessionCaches(draft, sessionIDs) + }), + ) + clearMeta(directory, sessionIDs) + } + + const touch = (directory: string, setStore: Setter, sessionID: string) => { + const stale = pickSessionCacheEvictions({ + seen: seenFor(directory), + keep: sessionID, + limit: SESSION_CACHE_LIMIT, + }) + evict(directory, setStore, stale) + } + const fetchMessages = async (input: { client: typeof sdk.client; sessionID: string; limit: number }) => { const messages = await retry(() => input.client.session.messages({ sessionID: input.sessionID, limit: input.limit }), @@ -135,6 +194,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ } } + const tracked = (directory: string, sessionID: string) => seen.get(directory)?.has(sessionID) ?? false + const loadMessages = async (input: { directory: string client: typeof sdk.client @@ -148,6 +209,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ setMeta("loading", key, true) await fetchMessages(input) .then((next) => { + if (!tracked(input.directory, input.sessionID)) return batch(() => { input.setStore("message", input.sessionID, reconcile(next.session, { key: "id" })) for (const p of next.part) { @@ -158,6 +220,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ }) }) .finally(() => { + if (!tracked(input.directory, input.sessionID)) return setMeta("loading", key, false) }) } @@ -199,6 +262,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ parts: Part[] agent: string model: { providerID: string; modelID: string } + variant?: string }) { const message: Message = { id: input.messageID, @@ -207,6 +271,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ time: { created: Date.now() }, agent: input.agent, model: input.model, + variant: input.variant, } const [, setStore] = target() setOptimisticAdd(setStore as (...args: unknown[]) => void, { @@ -222,11 +287,16 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const key = keyFor(directory, sessionID) const hasSession = Binary.search(store.session, sessionID, (s) => s.id).found + touch(directory, setStore, sessionID) + + if (store.message[sessionID] !== undefined && hasSession && meta.limit[key] !== undefined) return + const limit = meta.limit[key] ?? messagePageSize const sessionReq = hasSession ? Promise.resolve() : retry(() => client.session.get({ sessionID })).then((session) => { + if (!tracked(directory, sessionID)) return const data = session.data if (!data) return setStore( @@ -256,11 +326,13 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const directory = sdk.directory const client = sdk.client const [store, setStore] = globalSync.child(directory) + touch(directory, setStore, sessionID) if (store.session_diff[sessionID] !== undefined) return const key = keyFor(directory, sessionID) return runInflight(inflightDiff, key, () => retry(() => client.session.diff({ sessionID })).then((diff) => { + if (!tracked(directory, sessionID)) return setStore("session_diff", sessionID, reconcile(diff.data ?? [], { key: "file" })) }), ) @@ -269,6 +341,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const directory = sdk.directory const client = sdk.client const [store, setStore] = globalSync.child(directory) + touch(directory, setStore, sessionID) const existing = store.todo[sessionID] const cached = globalSync.data.session_todo[sessionID] if (existing !== undefined) { @@ -285,6 +358,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const key = keyFor(directory, sessionID) return runInflight(inflightTodo, key, () => retry(() => client.session.todo({ sessionID })).then((todo) => { + if (!tracked(directory, sessionID)) return const list = todo.data ?? [] setStore("todo", sessionID, reconcile(list, { key: "id" })) globalSync.todo.set(sessionID, list) @@ -308,6 +382,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const directory = sdk.directory const client = sdk.client const [, setStore] = globalSync.child(directory) + touch(directory, setStore, sessionID) const key = keyFor(directory, sessionID) const step = count ?? messagePageSize if (meta.loading[key]) return @@ -323,6 +398,11 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ }) }, }, + evict(sessionID: string, directory = sdk.directory) { + const [, setStore] = globalSync.child(directory) + seenFor(directory).delete(sessionID) + evict(directory, setStore, [sessionID]) + }, fetch: async (count = 10) => { const directory = sdk.directory const client = sdk.client diff --git a/packages/app/src/context/terminal.tsx b/packages/app/src/context/terminal.tsx index 64f026219ab..4467495b79d 100644 --- a/packages/app/src/context/terminal.tsx +++ b/packages/app/src/context/terminal.tsx @@ -1,6 +1,6 @@ import { createStore, produce } from "solid-js/store" import { createSimpleContext } from "@opencode-ai/ui/context" -import { batch, createEffect, createMemo, createRoot, onCleanup } from "solid-js" +import { batch, createEffect, createMemo, createRoot, on, onCleanup } from "solid-js" import { useParams } from "@solidjs/router" import { useSDK } from "./sdk" import type { Platform } from "./platform" @@ -38,6 +38,16 @@ type TerminalCacheEntry = { const caches = new Set>() +const trimTerminal = (pty: LocalPTY) => { + if (!pty.buffer && pty.cursor === undefined && pty.scrollY === undefined) return pty + return { + ...pty, + buffer: undefined, + cursor: undefined, + scrollY: undefined, + } +} + export function clearWorkspaceTerminals(dir: string, sessionIDs?: string[], platform?: Platform) { const key = getWorkspaceTerminalCacheKey(dir) for (const cache of caches) { @@ -188,6 +198,18 @@ function createWorkspaceTerminalSession(sdk: ReturnType, dir: str console.error("Failed to update terminal", error) }) }, + trim(id: string) { + const index = store.all.findIndex((x) => x.id === id) + if (index === -1) return + setStore("all", index, (pty) => trimTerminal(pty)) + }, + trimAll() { + setStore("all", (all) => { + const next = all.map(trimTerminal) + if (next.every((pty, index) => pty === all[index])) return all + return next + }) + }, async clone(id: string) { const index = store.all.findIndex((x) => x.id === id) const pty = store.all[index] @@ -322,12 +344,27 @@ export const { use: useTerminal, provider: TerminalProvider } = createSimpleCont const workspace = createMemo(() => loadWorkspace(params.dir!, params.id)) + createEffect( + on( + () => ({ dir: params.dir, id: params.id }), + (next, prev) => { + if (!prev?.dir) return + if (next.dir === prev.dir && next.id === prev.id) return + if (next.dir === prev.dir && next.id) return + loadWorkspace(prev.dir, prev.id).trimAll() + }, + { defer: true }, + ), + ) + return { ready: () => workspace().ready(), all: () => workspace().all(), active: () => workspace().active(), new: () => workspace().new(), update: (pty: Partial & { id: string }) => workspace().update(pty), + trim: (id: string) => workspace().trim(id), + trimAll: () => workspace().trimAll(), clone: (id: string) => workspace().clone(id), open: (id: string) => workspace().open(id), close: (id: string) => workspace().close(id), diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index edf33607314..6e5d16775b9 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -455,6 +455,7 @@ export const dict = { "session.todo.title": "المهام", "session.todo.collapse": "طي", "session.todo.expand": "توسيع", + "session.new.title": "ابنِ أي شيء", "session.new.worktree.main": "الفرع الرئيسي", "session.new.worktree.mainWithBranch": "الفرع الرئيسي ({{branch}})", "session.new.worktree.create": "إنشاء شجرة عمل جديدة", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 55753571d6b..64621559996 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -459,6 +459,7 @@ export const dict = { "session.todo.title": "Tarefas", "session.todo.collapse": "Recolher", "session.todo.expand": "Expandir", + "session.new.title": "Crie qualquer coisa", "session.new.worktree.main": "Branch principal", "session.new.worktree.mainWithBranch": "Branch principal ({{branch}})", "session.new.worktree.create": "Criar novo worktree", diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index 93d499d9e99..0fae276cd46 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -113,7 +113,6 @@ export const dict = { "dialog.model.empty": "Nema rezultata za modele", "dialog.model.manage": "Upravljaj modelima", "dialog.model.manage.description": "Prilagodi koji se modeli prikazuju u izborniku modela.", - "dialog.model.manage.provider.toggle": "Uključi/isključi sve {{provider}} modele", "dialog.model.unpaid.freeModels.title": "Besplatni modeli koje obezbjeđuje Kilo", "dialog.model.unpaid.addMore.title": "Dodaj još modela od popularnih provajdera", @@ -500,7 +499,6 @@ export const dict = { "session.review.loadingChanges": "Učitavanje izmjena...", "session.review.empty": "Još nema izmjena u ovoj sesiji", "session.review.noChanges": "Nema izmjena", - "session.review.noVcs": "Nije otkriven git VCS, stoga promjene sesije neće biti detektovane", "session.files.selectToOpen": "Odaberi datoteku za otvaranje", "session.files.all": "Sve datoteke", @@ -517,11 +515,7 @@ export const dict = { "session.todo.collapse": "Sažmi", "session.todo.expand": "Proširi", - "session.modeSwitch.switching": "Prebacivanje u {{mode}} način rada…", - "session.modeSwitch.waiting": "Čekanje na završetak trenutnog zadatka", - "session.modeSwitch.notAvailable": "Agent nije dostupan", - "session.modeSwitch.fallback": '"{{requested}}" nije pronađen, koristi se "{{actual}}"', - + "session.new.title": "Napravi bilo šta", "session.new.worktree.main": "Glavna grana", "session.new.worktree.mainWithBranch": "Glavna grana ({{branch}})", "session.new.worktree.create": "Kreiraj novi worktree", @@ -619,8 +613,6 @@ export const dict = { "settings.general.row.theme.description": "Prilagodi temu Kilo-a.", "settings.general.row.font.title": "Font", "settings.general.row.font.description": "Prilagodi monospace font koji se koristi u blokovima koda", - "settings.general.row.reasoningSummaries.title": "Prikaži sažetke razmišljanja", - "settings.general.row.reasoningSummaries.description": "Prikaži sažetke razmišljanja modela u vremenskoj liniji", "settings.general.row.shellToolPartsExpanded.title": "Proširi dijelove shell alata", "settings.general.row.shellToolPartsExpanded.description": diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index fa3cd900e55..57729d59b91 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -113,7 +113,6 @@ export const dict = { "dialog.model.empty": "Ingen modeller fundet", "dialog.model.manage": "Administrer modeller", "dialog.model.manage.description": "Tilpas hvilke modeller der vises i modelvælgeren.", - "dialog.model.manage.provider.toggle": "Skift alle {{provider}}-modeller", "dialog.model.unpaid.freeModels.title": "Gratis modeller leveret af Kilo", "dialog.model.unpaid.addMore.title": "Tilføj flere modeller fra populære udbydere", @@ -497,7 +496,6 @@ export const dict = { "session.review.loadingChanges": "Indlæser ændringer...", "session.review.empty": "Ingen ændringer i denne session endnu", "session.review.noChanges": "Ingen ændringer", - "session.review.noVcs": "Ingen git VCS registreret, så sessionsændringer vil ikke blive registreret", "session.files.selectToOpen": "Vælg en fil at åbne", "session.files.all": "Alle filer", "session.files.binaryContent": "Binær fil (indhold kan ikke vises)", @@ -512,11 +510,7 @@ export const dict = { "session.todo.collapse": "Skjul", "session.todo.expand": "Udvid", - "session.modeSwitch.switching": "Skifter til {{mode}}-tilstand…", - "session.modeSwitch.waiting": "Venter på at den aktuelle opgave er fuldført", - "session.modeSwitch.notAvailable": "Agent ikke tilgængelig", - "session.modeSwitch.fallback": '"{{requested}}" ikke fundet, bruger "{{actual}}"', - + "session.new.title": "Byg hvad som helst", "session.new.worktree.main": "Hovedgren", "session.new.worktree.mainWithBranch": "Hovedgren ({{branch}})", "session.new.worktree.create": "Opret nyt worktree", @@ -614,8 +608,6 @@ export const dict = { "settings.general.row.theme.description": "Tilpas hvordan Kilo er temabestemt.", "settings.general.row.font.title": "Skrifttype", "settings.general.row.font.description": "Tilpas mono-skrifttypen brugt i kodeblokke", - "settings.general.row.reasoningSummaries.title": "Vis ræsonneringssammendrag", - "settings.general.row.reasoningSummaries.description": "Vis modelræsonneringssammendrag i tidslinjen", "settings.general.row.shellToolPartsExpanded.title": "Udvid shell-værktøjsdele", "settings.general.row.shellToolPartsExpanded.description": "Vis shell-værktøjsdele udvidet som standard i tidslinjen", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index 9c4b8ccff2e..2be8c6a3840 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -467,6 +467,7 @@ export const dict = { "session.todo.title": "Aufgaben", "session.todo.collapse": "Einklappen", "session.todo.expand": "Ausklappen", + "session.new.title": "Baue, was du willst", "session.new.worktree.main": "Haupt-Branch", "session.new.worktree.mainWithBranch": "Haupt-Branch ({{branch}})", "session.new.worktree.create": "Neuen Worktree erstellen", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 213d17a8abe..f4b7589747b 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -402,6 +402,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.nl": "Nederlands", "language.th": "ไทย", "language.tr": "Türkçe", @@ -511,11 +512,13 @@ export const dict = { "session.review.change.other": "Changes", "session.review.loadingChanges": "Loading changes...", "session.review.empty": "No changes in this session yet", - "session.review.noVcs": "No git VCS detected, so session changes will not be detected", + "session.review.noVcs": "No Git Version Control System detected, changes not displayed", + "session.review.noSnapshot": "Snapshot tracking is disabled in config, so session changes are unavailable", "session.review.noChanges": "No changes", "session.files.selectToOpen": "Select a file to open", "session.files.all": "All files", + "session.files.empty": "No files", "session.files.binaryContent": "Binary file (content cannot be displayed)", "session.messages.renderEarlier": "Render earlier messages", @@ -529,11 +532,7 @@ export const dict = { "session.todo.collapse": "Collapse", "session.todo.expand": "Expand", - "session.modeSwitch.switching": "Switching to {{mode}} mode…", - "session.modeSwitch.waiting": "Waiting for current task to complete", - "session.modeSwitch.notAvailable": "Agent not available", - "session.modeSwitch.fallback": '"{{requested}}" not found, using "{{actual}}"', - + "session.new.title": "Build anything", "session.new.worktree.main": "Main branch", "session.new.worktree.mainWithBranch": "Main branch ({{branch}})", "session.new.worktree.create": "Create new worktree", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index a4733422030..3152643c5b9 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -113,7 +113,6 @@ export const dict = { "dialog.model.empty": "Sin resultados de modelos", "dialog.model.manage": "Gestionar modelos", "dialog.model.manage.description": "Personalizar qué modelos aparecen en el selector de modelos.", - "dialog.model.manage.provider.toggle": "Alternar todos los modelos de {{provider}}", "dialog.model.unpaid.freeModels.title": "Modelos gratuitos proporcionados por Kilo", "dialog.model.unpaid.addMore.title": "Añadir más modelos de proveedores populares", @@ -501,7 +500,6 @@ export const dict = { "session.review.loadingChanges": "Cargando cambios...", "session.review.empty": "No hay cambios en esta sesión aún", "session.review.noChanges": "Sin cambios", - "session.review.noVcs": "No se detectó VCS de git, por lo que los cambios de sesión no se detectarán", "session.files.selectToOpen": "Selecciona un archivo para abrir", "session.files.all": "Todos los archivos", @@ -518,11 +516,7 @@ export const dict = { "session.todo.collapse": "Contraer", "session.todo.expand": "Expandir", - "session.modeSwitch.switching": "Cambiando al modo {{mode}}…", - "session.modeSwitch.waiting": "Esperando que la tarea actual se complete", - "session.modeSwitch.notAvailable": "Agente no disponible", - "session.modeSwitch.fallback": '"{{requested}}" no encontrado, usando "{{actual}}"', - + "session.new.title": "Construye lo que quieras", "session.new.worktree.main": "Rama principal", "session.new.worktree.mainWithBranch": "Rama principal ({{branch}})", "session.new.worktree.create": "Crear nuevo árbol de trabajo", @@ -622,9 +616,6 @@ export const dict = { "settings.general.row.theme.description": "Personaliza el tema de Kilo.", "settings.general.row.font.title": "Fuente", "settings.general.row.font.description": "Personaliza la fuente monoespaciada usada en bloques de código", - "settings.general.row.reasoningSummaries.title": "Mostrar resúmenes de razonamiento", - "settings.general.row.reasoningSummaries.description": - "Mostrar resúmenes de razonamiento del modelo en la línea de tiempo", "settings.general.row.shellToolPartsExpanded.title": "Expandir partes de la herramienta shell", "settings.general.row.shellToolPartsExpanded.description": diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index f939b222814..f0d7724ef01 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -462,6 +462,7 @@ export const dict = { "session.todo.title": "Tâches", "session.todo.collapse": "Réduire", "session.todo.expand": "Développer", + "session.new.title": "Créez ce que vous voulez", "session.new.worktree.main": "Branche principale", "session.new.worktree.mainWithBranch": "Branche principale ({{branch}})", "session.new.worktree.create": "Créer un nouvel arbre de travail", @@ -551,9 +552,6 @@ export const dict = { "settings.general.row.theme.description": "Personnaliser le thème d'Kilo.", "settings.general.row.font.title": "Police", "settings.general.row.font.description": "Personnaliser la police mono utilisée dans les blocs de code", - "settings.general.row.reasoningSummaries.title": "Afficher les résumés de raisonnement", - "settings.general.row.reasoningSummaries.description": - "Afficher les résumés de raisonnement du modèle dans la chronologie", "settings.general.row.shellToolPartsExpanded.title": "Développer les parties de l'outil shell", "settings.general.row.shellToolPartsExpanded.description": "Afficher les parties de l'outil shell développées par défaut dans la chronologie", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index 68cc9b4045c..bef17be027d 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -457,6 +457,7 @@ export const dict = { "session.todo.title": "ToDo", "session.todo.collapse": "折りたたむ", "session.todo.expand": "展開", + "session.new.title": "何でも作る", "session.new.worktree.main": "メインブランチ", "session.new.worktree.mainWithBranch": "メインブランチ ({{branch}})", "session.new.worktree.create": "新しいワークツリーを作成", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index 35f1c521140..bf8ecf67e6f 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -459,6 +459,7 @@ export const dict = { "session.todo.title": "할 일", "session.todo.collapse": "접기", "session.todo.expand": "펼치기", + "session.new.title": "무엇이든 만들기", "session.new.worktree.main": "메인 브랜치", "session.new.worktree.mainWithBranch": "메인 브랜치 ({{branch}})", "session.new.worktree.create": "새 작업 트리 생성", diff --git a/packages/app/src/i18n/nl.ts b/packages/app/src/i18n/nl.ts new file mode 100644 index 00000000000..376aaa42bbf --- /dev/null +++ b/packages/app/src/i18n/nl.ts @@ -0,0 +1,855 @@ +export const dict = { + "command.category.suggested": "Voorgesteld", + "command.category.view": "Weergave", + "command.category.project": "Project", + "command.category.provider": "Provider", + "command.category.server": "Server", + "command.category.session": "Sessie", + "command.category.theme": "Thema", + "command.category.language": "Taal", + "command.category.file": "Bestand", + "command.category.context": "Context", + "command.category.terminal": "Terminal", + "command.category.model": "Model", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Machtigingen", + "command.category.workspace": "Werkruimte", + "command.category.settings": "Instellingen", + + "theme.scheme.system": "Systeem", + "theme.scheme.light": "Licht", + "theme.scheme.dark": "Donker", + + "command.sidebar.toggle": "Zijbalk in-/uitschakelen", + "command.project.open": "Project openen", + "command.provider.connect": "Provider verbinden", + "command.server.switch": "Server wisselen", + "command.settings.open": "Instellingen openen", + "command.session.previous": "Vorige sessie", + "command.session.next": "Volgende sessie", + "command.session.previous.unseen": "Vorige ongelezen sessie", + "command.session.next.unseen": "Volgende ongelezen sessie", + "command.session.archive": "Sessie archiveren", + + "command.palette": "Opdrachtenpalet", + + "command.theme.cycle": "Volgend thema", + "command.theme.set": "Gebruik thema: {{theme}}", + "command.theme.scheme.cycle": "Volgend kleurenschema", + "command.theme.scheme.set": "Gebruik kleurenschema: {{scheme}}", + + "command.language.cycle": "Volgende taal", + "command.language.set": "Gebruik taal: {{language}}", + + "command.session.new": "Nieuwe sessie", + "command.file.open": "Bestand openen", + "command.tab.close": "Tabblad sluiten", + "command.context.addSelection": "Selectie toevoegen aan context", + "command.context.addSelection.description": "Geselecteerde regels van het huidige bestand toevoegen", + "command.input.focus": "Invoer focussen", + "command.terminal.toggle": "Terminal in-/uitschakelen", + "command.fileTree.toggle": "Bestandsboom in-/uitschakelen", + "command.review.toggle": "Review in-/uitschakelen", + "command.terminal.new": "Nieuwe terminal", + "command.terminal.new.description": "Een nieuw terminal-tabblad maken", + "command.steps.toggle": "Stappen in-/uitschakelen", + "command.steps.toggle.description": "Stappen voor het huidige bericht tonen of verbergen", + "command.message.previous": "Vorig bericht", + "command.message.previous.description": "Ga naar het vorige gebruikersbericht", + "command.message.next": "Volgend bericht", + "command.message.next.description": "Ga naar het volgende gebruikersbericht", + "command.model.choose": "Model kiezen", + "command.model.choose.description": "Selecteer een ander model", + "command.mcp.toggle": "MCPs in-/uitschakelen", + "command.mcp.toggle.description": "MCPs in-/uitschakelen", + "command.agent.cycle": "Volgende agent", + "command.agent.cycle.description": "Overschakelen naar de volgende agent", + "command.agent.cycle.reverse": "Vorige agent", + "command.agent.cycle.reverse.description": "Overschakelen naar de vorige agent", + "command.model.variant.cycle": "Volgende denkinspanning", + "command.model.variant.cycle.description": "Overschakelen naar het volgende inspanningsniveau", + "command.prompt.mode.shell": "Shell", + "command.prompt.mode.normal": "Prompt", + "command.permissions.autoaccept.enable": "Machtigingen automatisch accepteren", + "command.permissions.autoaccept.disable": "Machtigingen niet langer automatisch accepteren", + "command.workspace.toggle": "Werkruimtes in-/uitschakelen", + "command.workspace.toggle.description": "Meerdere werkruimtes in de zijbalk in- of uitschakelen", + "command.session.undo": "Ongedaan maken", + "command.session.undo.description": "Laatste bericht ongedaan maken", + "command.session.redo": "Opnieuw uitvoeren", + "command.session.redo.description": "Het laatst ongedaan gemaakte bericht opnieuw uitvoeren", + "command.session.compact": "Sessie comprimeren", + "command.session.compact.description": "Sessie samenvatten om contextgrootte te verkleinen", + "command.session.fork": "Afsplitsen van bericht", + "command.session.fork.description": "Nieuwe sessie maken van een eerder bericht", + "command.session.share": "Sessie delen", + "command.session.share.description": "Deze sessie delen en de URL naar klembord kopiëren", + "command.session.unshare": "Sessie niet meer delen", + "command.session.unshare.description": "Stoppen met het delen van deze sessie", + + "palette.search.placeholder": "Zoek bestanden, opdrachten en sessies", + "palette.empty": "Geen resultaten gevonden", + "palette.group.commands": "Opdrachten", + "palette.group.files": "Bestanden", + + "dialog.provider.search.placeholder": "Zoek providers", + "dialog.provider.empty": "Geen providers gevonden", + "dialog.provider.group.popular": "Populair", + "dialog.provider.group.other": "Overig", + "dialog.provider.tag.recommended": "Aanbevolen", + "dialog.provider.opencode.note": "Geselecteerde modellen inclusief Claude, GPT, Gemini en meer", + "dialog.provider.opencode.tagline": "Betrouwbare geoptimaliseerde modellen", + "dialog.provider.opencodeGo.tagline": "Goedkoop abonnement voor iedereen", + "dialog.provider.anthropic.note": "Directe toegang tot Claude modellen, inclusief Pro en Max", + "dialog.provider.copilot.note": "AI-modellen voor codeerassistentie via GitHub Copilot", + "dialog.provider.openai.note": "GPT modellen voor snelle, capabele algemene AI-taken", + "dialog.provider.google.note": "Gemini modellen voor snelle, gestructureerde antwoorden", + "dialog.provider.openrouter.note": "Toegang tot alle ondersteunde modellen via één provider", + "dialog.provider.vercel.note": "Geünificeerde toegang tot AI-modellen met slimme routering", + + "dialog.model.select.title": "Selecteer model", + "dialog.model.search.placeholder": "Zoek modellen", + "dialog.model.empty": "Geen modelresultaten", + "dialog.model.manage": "Modellen beheren", + "dialog.model.manage.description": "Pas aan welke modellen in de modelkiezer verschijnen.", + "dialog.model.manage.provider.toggle": "Alle {{provider}} modellen in-/uitschakelen", + + "dialog.model.unpaid.freeModels.title": "Gratis modellen aangeboden door Kilo", + "dialog.model.unpaid.addMore.title": "Meer modellen toevoegen van populaire providers", + + "dialog.provider.viewAll": "Toon meer providers", + + "provider.connect.title": "{{provider}} verbinden", + "provider.connect.title.anthropicProMax": "Inloggen met Claude Pro/Max", + "provider.connect.selectMethod": "Selecteer inlogmethode voor {{provider}}.", + "provider.connect.method.apiKey": "API key", + "provider.connect.status.inProgress": "Autorisatie in uitvoering...", + "provider.connect.status.waiting": "Wachten op autorisatie...", + "provider.connect.status.failed": "Autorisatie mislukt: {{error}}", + "provider.connect.apiKey.description": + "Voer uw {{provider}} API key in om uw account te verbinden en {{provider}} modellen te gebruiken in Kilo.", + "provider.connect.apiKey.label": "{{provider}} API key", + "provider.connect.apiKey.placeholder": "API key", + "provider.connect.apiKey.required": "API key is vereist", + "provider.connect.opencodeZen.line1": + "OpenCode Zen geeft u toegang tot een geselecteerde set betrouwbare en geoptimaliseerde modellen voor coderingsagenten.", + "provider.connect.opencodeZen.line2": + "Met een enkele API key krijgt u toegang tot modellen zoals Claude, GPT, Gemini, GLM en meer.", + "provider.connect.opencodeZen.visit.prefix": "Bezoek ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " om uw API key te verkrijgen.", + "provider.connect.oauth.code.visit.prefix": "Bezoek ", + "provider.connect.oauth.code.visit.link": "deze link", + "provider.connect.oauth.code.visit.suffix": + " om uw autorisatiecode te verkrijgen, uw account te verbinden en {{provider}} modellen te gebruiken in Kilo.", + "provider.connect.oauth.code.label": "{{method}} autorisatiecode", + "provider.connect.oauth.code.placeholder": "Autorisatiecode", + "provider.connect.oauth.code.required": "Autorisatiecode is vereist", + "provider.connect.oauth.code.invalid": "Ongeldige autorisatiecode", + "provider.connect.oauth.auto.visit.prefix": "Bezoek ", + "provider.connect.oauth.auto.visit.link": "deze link", + "provider.connect.oauth.auto.visit.suffix": + " en voer de onderstaande code in om uw account te verbinden en {{provider}} modellen te gebruiken in Kilo.", + "provider.connect.oauth.auto.confirmationCode": "Bevestigingscode", + "provider.connect.toast.connected.title": "{{provider}} verbonden", + "provider.connect.toast.connected.description": "{{provider}} modellen zijn nu beschikbaar om te gebruiken.", + + "provider.custom.title": "Aangepaste provider", + "provider.custom.description.prefix": "Configureer een OpenAI-compatibele provider. Zie de ", + "provider.custom.description.link": "provider configuratiedocumentatie", + "provider.custom.description.suffix": ".", + "provider.custom.field.providerID.label": "Provider ID", + "provider.custom.field.providerID.placeholder": "myprovider", + "provider.custom.field.providerID.description": "Kleine letters, cijfers, koppeltekens of underscores", + "provider.custom.field.name.label": "Weergavenaam", + "provider.custom.field.name.placeholder": "Mijn AI Provider", + "provider.custom.field.baseURL.label": "Basis-URL", + "provider.custom.field.baseURL.placeholder": "https://api.myprovider.com/v1", + "provider.custom.field.apiKey.label": "API key", + "provider.custom.field.apiKey.placeholder": "API key", + "provider.custom.field.apiKey.description": "Optioneel. Laat leeg als u auth via headers beheert.", + "provider.custom.models.label": "Modellen", + "provider.custom.models.id.label": "ID", + "provider.custom.models.id.placeholder": "model-id", + "provider.custom.models.name.label": "Naam", + "provider.custom.models.name.placeholder": "Weergavenaam", + "provider.custom.models.remove": "Model verwijderen", + "provider.custom.models.add": "Model toevoegen", + "provider.custom.headers.label": "Headers (optioneel)", + "provider.custom.headers.key.label": "Header", + "provider.custom.headers.key.placeholder": "Header-Naam", + "provider.custom.headers.value.label": "Waarde", + "provider.custom.headers.value.placeholder": "waarde", + "provider.custom.headers.remove": "Header verwijderen", + "provider.custom.headers.add": "Header toevoegen", + "provider.custom.error.providerID.required": "Provider ID is vereist", + "provider.custom.error.providerID.format": "Gebruik kleine letters, cijfers, koppeltekens of underscores", + "provider.custom.error.providerID.exists": "Deze provider ID bestaat al", + "provider.custom.error.name.required": "Weergavenaam is vereist", + "provider.custom.error.baseURL.required": "Basis-URL is vereist", + "provider.custom.error.baseURL.format": "Moet beginnen met http:// of https://", + "provider.custom.error.required": "Vereist", + "provider.custom.error.duplicate": "Duplicaat", + + "provider.disconnect.toast.disconnected.title": "{{provider}} losgekoppeld", + "provider.disconnect.toast.disconnected.description": "{{provider}} modellen zijn niet langer beschikbaar.", + + "model.tag.free": "Gratis", + "model.tag.latest": "Nieuwste", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "tekst", + "model.input.image": "afbeelding", + "model.input.audio": "audio", + "model.input.video": "video", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Staat toe: {{inputs}}", + "model.tooltip.reasoning.allowed": "Staat redenering toe", + "model.tooltip.reasoning.none": "Geen redenering", + "model.tooltip.context": "Contextlimiet {{limit}}", + + "common.search.placeholder": "Zoeken", + "common.goBack": "Ga terug", + "common.goForward": "Ga vooruit", + "common.loading": "Laden", + "common.loading.ellipsis": "...", + "common.cancel": "Annuleren", + "common.open": "Openen", + "common.connect": "Verbinden", + "common.disconnect": "Loskoppelen", + "common.submit": "Verzenden", + "common.save": "Opslaan", + "common.saving": "Opslaan...", + "common.default": "Standaard", + "common.attachment": "bijlage", + + "prompt.placeholder.shell": "Voer shell-opdracht in...", + "prompt.placeholder.normal": 'Vraag alles... "{{example}}"', + "prompt.placeholder.simple": "Vraag alles...", + "prompt.placeholder.summarizeComments": "Reacties samenvatten...", + "prompt.placeholder.summarizeComment": "Reactie samenvatten...", + "prompt.mode.shell": "Shell", + "prompt.mode.normal": "Prompt", + "prompt.mode.shell.exit": "esc om te verlaten", + + "prompt.example.1": "Fix een TODO in de codebase", + "prompt.example.2": "Wat is de tech stack van dit project?", + "prompt.example.3": "Repareer kapotte tests", + "prompt.example.4": "Leg uit hoe authenticatie werkt", + "prompt.example.5": "Vind en herstel beveiligingskwetsbaarheden", + "prompt.example.6": "Voeg unittests toe voor de gebruikersservice", + "prompt.example.7": "Herschrijf deze functie om deze beter leesbaar te maken", + "prompt.example.8": "Wat betekent deze fout?", + "prompt.example.9": "Help me met het debuggen van dit probleem", + "prompt.example.10": "Genereer API-documentatie", + "prompt.example.11": "Optimaliseer databasequery's", + "prompt.example.12": "Voeg invoervalidatie toe", + "prompt.example.13": "Maak een nieuwe component voor...", + "prompt.example.14": "Hoe implementeer ik dit project?", + "prompt.example.15": "Bekijk mijn code voor best practices", + "prompt.example.16": "Voeg foutafhandeling toe aan deze functie", + "prompt.example.17": "Leg dit regex-patroon uit", + "prompt.example.18": "Zet dit om naar TypeScript", + "prompt.example.19": "Voeg logging toe in de hele codebase", + "prompt.example.20": "Welke afhankelijkheden zijn verouderd?", + "prompt.example.21": "Help me een migratiescript te schrijven", + "prompt.example.22": "Implementeer caching voor dit eindpunt", + "prompt.example.23": "Voeg paginering toe aan deze lijst", + "prompt.example.24": "Maak een CLI-opdracht voor...", + "prompt.example.25": "Hoe werken omgevingsvariabelen hier?", + + "prompt.popover.emptyResults": "Geen overeenkomende resultaten", + "prompt.popover.emptyCommands": "Geen overeenkomende opdrachten", + "prompt.dropzone.label": "Sleep afbeeldingen of PDF's hierheen", + "prompt.dropzone.file.label": "Sleep om bestand te @vermelden", + "prompt.slash.badge.custom": "aangepast", + "prompt.slash.badge.skill": "skill", + "prompt.slash.badge.mcp": "mcp", + "prompt.context.active": "actief", + "prompt.context.includeActiveFile": "Neem actief bestand op", + "prompt.context.removeActiveFile": "Verwijder actief bestand uit context", + "prompt.context.removeFile": "Verwijder bestand uit context", + "prompt.action.attachFile": "Bestand toevoegen", + "prompt.attachment.remove": "Bijlage verwijderen", + "prompt.action.send": "Verzenden", + "prompt.action.stop": "Stop", + + "prompt.toast.pasteUnsupported.title": "Niet-ondersteunde plakbewerking", + "prompt.toast.pasteUnsupported.description": "Hier kunnen alleen afbeeldingen of PDF's worden geplakt.", + "prompt.toast.modelAgentRequired.title": "Selecteer een agent en model", + "prompt.toast.modelAgentRequired.description": "Kies een agent en model voordat u een prompt verzendt.", + "prompt.toast.worktreeCreateFailed.title": "Maken van worktree mislukt", + "prompt.toast.sessionCreateFailed.title": "Maken van sessie mislukt", + "prompt.toast.shellSendFailed.title": "Verzenden van shell-opdracht mislukt", + "prompt.toast.commandSendFailed.title": "Verzenden van opdracht mislukt", + "prompt.toast.promptSendFailed.title": "Verzenden van prompt mislukt", + "prompt.toast.promptSendFailed.description": "Kan sessie niet ophalen", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} van {{total}} ingeschakeld", + "dialog.mcp.empty": "Geen MCP's geconfigureerd", + + "dialog.lsp.empty": "LSP's automatisch gedetecteerd aan de hand van bestandstypen", + "dialog.plugins.empty": "Plug-ins geconfigureerd in opencode.json", + + "mcp.status.connected": "verbonden", + "mcp.status.failed": "mislukt", + "mcp.status.needs_auth": "authenticatie vereist", + "mcp.status.disabled": "uitgeschakeld", + + "dialog.fork.empty": "Geen berichten om van af te splitsen", + + "dialog.directory.search.placeholder": "Zoek mappen", + "dialog.directory.empty": "Geen mappen gevonden", + + "dialog.server.title": "Servers", + "dialog.server.description": "Wissel met welke Kilo server deze app verbindt.", + "dialog.server.search.placeholder": "Zoek servers", + "dialog.server.empty": "Nog geen servers", + "dialog.server.add.title": "Server toevoegen", + "dialog.server.add.url": "Serveradres", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Kan geen verbinding maken met server", + "dialog.server.add.checking": "Controleren...", + "dialog.server.add.button": "Server toevoegen", + "dialog.server.add.name": "Servernaam (optioneel)", + "dialog.server.add.namePlaceholder": "Localhost", + "dialog.server.add.username": "Gebruikersnaam (optioneel)", + "dialog.server.add.password": "Wachtwoord (optioneel)", + "dialog.server.edit.title": "Server bewerken", + "dialog.server.default.title": "Standaardserver", + "dialog.server.default.description": + "Maak verbinding met deze server bij de lancering van de app in plaats van een lokale server te starten. Vereist een herstart.", + "dialog.server.default.none": "Geen server geselecteerd", + "dialog.server.default.set": "Huidige server als standaard instellen", + "dialog.server.default.clear": "Wissen", + "dialog.server.action.remove": "Server verwijderen", + + "dialog.server.menu.edit": "Bewerken", + "dialog.server.menu.default": "Als standaard instellen", + "dialog.server.menu.defaultRemove": "Standaard verwijderen", + "dialog.server.menu.delete": "Verwijderen", + "dialog.server.current": "Huidige Server", + "dialog.server.status.default": "Standaard", + + "dialog.project.edit.title": "Project bewerken", + "dialog.project.edit.name": "Naam", + "dialog.project.edit.icon": "Icoon", + "dialog.project.edit.icon.alt": "Projecticoon", + "dialog.project.edit.icon.hint": "Klik of sleep een afbeelding", + "dialog.project.edit.icon.recommended": "Aanbevolen: 128x128px", + "dialog.project.edit.color": "Kleur", + "dialog.project.edit.color.select": "Selecteer {{color}} kleur", + "dialog.project.edit.worktree.startup": "Werkruimte opstartscript", + "dialog.project.edit.worktree.startup.description": + "Wordt uitgevoerd na het maken van een nieuwe werkruimte (worktree).", + "dialog.project.edit.worktree.startup.placeholder": "bijv. bun install", + + "dialog.releaseNotes.action.getStarted": "Aan de slag", + "dialog.releaseNotes.action.next": "Volgende", + "dialog.releaseNotes.action.hideFuture": "Toon deze niet in de toekomst", + "dialog.releaseNotes.media.alt": "Releasevoorbeeld", + + "context.breakdown.title": "Contextverdeling", + "context.breakdown.note": 'Geschatte verdeling van invoertokens. "Overig" bevat tooldefinities en overhead.', + "context.breakdown.system": "Systeem", + "context.breakdown.user": "Gebruiker", + "context.breakdown.assistant": "Assistent", + "context.breakdown.tool": "Tool-aanroepen", + "context.breakdown.other": "Overig", + + "context.systemPrompt.title": "Systeemprompt", + "context.rawMessages.title": "Ruwe berichten", + + "context.stats.session": "Sessie", + "context.stats.messages": "Berichten", + "context.stats.provider": "Provider", + "context.stats.model": "Model", + "context.stats.limit": "Contextlimiet", + "context.stats.totalTokens": "Totaal Tokens", + "context.stats.usage": "Gebruik", + "context.stats.inputTokens": "Invoertokens", + "context.stats.outputTokens": "Uitvoertokens", + "context.stats.reasoningTokens": "Redeneertokens", + "context.stats.cacheTokens": "Cachetokens (lezen/schrijven)", + "context.stats.userMessages": "Gebruikersberichten", + "context.stats.assistantMessages": "Assistentberichten", + "context.stats.totalCost": "Totale Kosten", + "context.stats.sessionCreated": "Sessie Aangemaakt", + "context.stats.lastActivity": "Laatste Activiteit", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Gebruik", + "context.usage.cost": "Kosten", + "context.usage.clickToView": "Klik om context te bekijken", + "context.usage.view": "Contextgebruik bekijken", + + "language.en": "English", + "language.zh": "简体中文", + "language.zht": "繁體中文", + "language.ko": "한국어", + "language.de": "Deutsch", + "language.es": "Español", + "language.fr": "Français", + "language.da": "Dansk", + "language.ja": "日本語", + "language.pl": "Polski", + "language.ru": "Русский", + "language.ar": "العربية", + "language.no": "Norsk", + "language.br": "Português (Brasil)", + "language.bs": "Bosanski", + "language.nl": "Nederlands", + "language.th": "ไทย", + "language.tr": "Türkçe", + + "toast.language.title": "Taal", + "toast.language.description": "Omgeschakeld naar {{language}}", + + "toast.theme.title": "Thema gewisseld", + "toast.scheme.title": "Kleurenschema", + + "toast.workspace.enabled.title": "Werkruimtes ingeschakeld", + "toast.workspace.enabled.description": "Meerdere worktrees worden nu weergegeven in de zijbalk", + "toast.workspace.disabled.title": "Werkruimtes uitgeschakeld", + "toast.workspace.disabled.description": "Alleen de hoofdworktree wordt weergegeven in de zijbalk", + + "toast.permissions.autoaccept.on.title": "Machtigingen automatisch accepteren", + "toast.permissions.autoaccept.on.description": "Toestemmingsverzoeken worden automatisch goedgekeurd", + "toast.permissions.autoaccept.off.title": "Gestopt met automatisch accepteren van machtigingen", + "toast.permissions.autoaccept.off.description": "Toestemmingsverzoeken vereisen goedkeuring", + + "toast.model.none.title": "Geen model geselecteerd", + "toast.model.none.description": "Verbind een provider om deze sessie samen te vatten", + + "toast.file.loadFailed.title": "Laden van bestand mislukt", + "toast.file.listFailed.title": "Lijst met bestanden ophalen mislukt", + + "toast.context.noLineSelection.title": "Geen regelselectie", + "toast.context.noLineSelection.description": "Selecteer eerst een regelbereik in een bestandstabblad.", + + "toast.session.share.copyFailed.title": "Kopiëren van URL naar klembord mislukt", + "toast.session.share.success.title": "Sessie gedeeld", + "toast.session.share.success.description": "Deel-URL naar klembord gekopieerd!", + "toast.session.share.failed.title": "Delen van sessie mislukt", + "toast.session.share.failed.description": "Er is een fout opgetreden bij het delen van de sessie", + + "toast.session.unshare.success.title": "Sessie niet meer gedeeld", + "toast.session.unshare.success.description": "Sessie succesvol niet meer gedeeld!", + "toast.session.unshare.failed.title": "Sessie niet meer delen mislukt", + "toast.session.unshare.failed.description": + "Er is een fout opgetreden bij het ongedaan maken van delen van de sessie", + + "toast.session.listFailed.title": "Laden van sessies voor {{project}} mislukt", + "toast.project.reloadFailed.title": "Herladen van {{project}} mislukt", + + "toast.update.title": "Update beschikbaar", + "toast.update.description": "Een nieuwe versie van Kilo ({{version}}) is nu beschikbaar om te installeren.", + "toast.update.action.installRestart": "Installeren en herstarten", + "toast.update.action.notYet": "Nog niet", + + "error.page.title": "Er is iets misgegaan", + "error.page.description": "Er is een fout opgetreden tijdens het laden van de applicatie.", + "error.page.details.label": "Foutdetails", + "error.page.action.restart": "Herstarten", + "error.page.action.checking": "Controleren...", + "error.page.action.checkUpdates": "Controleren op updates", + "error.page.action.updateTo": "Updaten naar {{version}}", + "error.page.report.prefix": "Meld deze fout alstublieft aan het Kilo team", + "error.page.report.discord": "op Discord", + "error.page.version": "Versie: {{version}}", + + "error.dev.rootNotFound": + "Root-element niet gevonden. Bent u vergeten dit toe te voegen aan uw index.html? Of misschien is het id-attribuut verkeerd gespeld?", + + "error.globalSync.connectFailed": "Kon geen verbinding maken met server. Draait er een server op `{{url}}`?", + "directory.error.invalidUrl": "Ongeldige map in URL.", + + "error.chain.unknown": "Onbekende fout", + "error.server.invalidConfiguration": "Ongeldige configuratie", + "error.chain.causedBy": "Veroorzaakt door:", + "error.chain.apiError": "API-fout", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Opnieuw te proberen: {{retryable}}", + "error.chain.responseBody": "Reactie-body:\n{{body}}", + "error.chain.didYouMean": "Bedoelde u: {{suggestions}}", + "error.chain.modelNotFound": "Model niet gevonden: {{provider}}/{{model}}", + "error.chain.checkConfig": "Controleer uw config (opencode.json) provider/modelnamen", + "error.chain.mcpFailed": 'MCP-server "{{name}}" is mislukt. Let op, Kilo ondersteunt nog geen MCP-authenticatie.', + "error.chain.providerAuthFailed": "Providerauthenticatie mislukt ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Initialiseren van provider "{{provider}}" mislukt. Controleer referenties en configuratie.', + "error.chain.configJsonInvalid": "Configuratiebestand op {{path}} is geen geldige JSON(C)", + "error.chain.configJsonInvalidWithMessage": "Configuratiebestand op {{path}} is geen geldige JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Map "{{dir}}" in {{path}} is niet geldig. Hernoem de map naar "{{suggestion}}" of verwijder deze. Dit is een veelvoorkomende typfout.', + "error.chain.configFrontmatterError": "Parsen van frontmatter mislukt in {{path}}:\n{{message}}", + "error.chain.configInvalid": "Configuratiebestand op {{path}} is ongeldig", + "error.chain.configInvalidWithMessage": "Configuratiebestand op {{path}} is ongeldig: {{message}}", + + "notification.permission.title": "Machtiging vereist", + "notification.permission.description": "{{sessionTitle}} in {{projectName}} heeft machtiging nodig", + "notification.question.title": "Vraag", + "notification.question.description": "{{sessionTitle}} in {{projectName}} heeft een vraag", + "notification.action.goToSession": "Ga naar sessie", + + "notification.session.responseReady.title": "Antwoord gereed", + "notification.session.error.title": "Sessiefout", + "notification.session.error.fallbackDescription": "Er is een fout opgetreden", + + "home.recentProjects": "Recente projecten", + "home.empty.title": "Geen recente projecten", + "home.empty.description": "Ga aan de slag door een lokaal project te openen", + + "session.tab.session": "Sessie", + "session.tab.review": "Review", + "session.tab.context": "Context", + "session.panel.reviewAndFiles": "Review en bestanden", + "session.review.filesChanged": "{{count}} Bestanden Gewijzigd", + "session.review.change.one": "Wijziging", + "session.review.change.other": "Wijzigingen", + "session.review.loadingChanges": "Wijzigingen laden...", + "session.review.empty": "Nog geen wijzigingen in deze sessie", + "session.review.noVcs": "Geen Git Version Control System gedetecteerd, wijzigingen niet weergegeven", + "session.review.noSnapshot": + "Snapshot-tracking is uitgeschakeld in configuratie, dus sessiewijzigingen zijn niet beschikbaar", + "session.review.noChanges": "Geen wijzigingen", + + "session.files.selectToOpen": "Selecteer een bestand om te openen", + "session.files.all": "Alle bestanden", + "session.files.empty": "Geen bestanden", + "session.files.binaryContent": "Binair bestand (inhoud kan niet worden weergegeven)", + + "session.messages.renderEarlier": "Eerdere berichten renderen", + "session.messages.loadingEarlier": "Eerdere berichten laden...", + "session.messages.loadEarlier": "Eerdere berichten laden", + "session.messages.loading": "Berichten laden...", + "session.messages.jumpToLatest": "Spring naar nieuwste", + + "session.context.addToContext": "Voeg {{selection}} toe aan context", + "session.todo.title": "To-do's", + "session.todo.collapse": "Inklappen", + "session.todo.expand": "Uitklappen", + + "session.new.title": "Bouw wat u wilt", + "session.new.worktree.main": "Hoofdbranch", + "session.new.worktree.mainWithBranch": "Hoofdbranch ({{branch}})", + "session.new.worktree.create": "Nieuwe worktree maken", + "session.new.lastModified": "Laatst gewijzigd", + + "session.header.search.placeholder": "Zoek {{project}}", + "session.header.searchFiles": "Zoek bestanden", + "session.header.openIn": "Openen in", + "session.header.open.action": "Open {{app}}", + "session.header.open.ariaLabel": "Openen in {{app}}", + "session.header.open.menu": "Open-opties", + "session.header.open.copyPath": "Pad kopiëren", + + "status.popover.trigger": "Status", + "status.popover.ariaLabel": "Serverconfiguraties", + "status.popover.tab.servers": "Servers", + "status.popover.tab.mcp": "MCP", + "status.popover.tab.lsp": "LSP", + "status.popover.tab.plugins": "Plug-ins", + "status.popover.action.manageServers": "Servers beheren", + + "session.share.popover.title": "Op web publiceren", + "session.share.popover.description.shared": + "Deze sessie is openbaar op het web. Het is toegankelijk voor iedereen met de link.", + "session.share.popover.description.unshared": + "Sessie openbaar delen op het web. Het zal toegankelijk zijn voor iedereen met de link.", + "session.share.action.share": "Delen", + "session.share.action.publish": "Publiceren", + "session.share.action.publishing": "Publiceren...", + "session.share.action.unpublish": "Publicatie ongedaan maken", + "session.share.action.unpublishing": "Publicatie ongedaan maken...", + "session.share.action.view": "Bekijken", + "session.share.copy.copied": "Gekopieerd", + "session.share.copy.copyLink": "Link kopiëren", + + "lsp.tooltip.none": "Geen LSP-servers", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Prompt laden...", + "terminal.loading": "Terminal laden...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Terminal sluiten", + "terminal.connectionLost.title": "Verbinding verbroken", + "terminal.connectionLost.description": + "De terminalverbinding is onderbroken. Dit kan gebeuren wanneer de server herstart.", + + "common.closeTab": "Tabblad sluiten", + "common.dismiss": "Negeren", + "common.moreCountSuffix": " (nog +{{count}})", + "common.requestFailed": "Verzoek mislukt", + "common.moreOptions": "Meer opties", + "common.learnMore": "Meer informatie", + "common.rename": "Hernoemen", + "common.reset": "Reset", + "common.archive": "Archiveren", + "common.delete": "Verwijderen", + "common.close": "Sluiten", + "common.edit": "Bewerken", + "common.loadMore": "Meer laden", + "common.key.esc": "ESC", + + "common.time.justNow": "Zojuist", + "common.time.minutesAgo.short": "{{count}}m geleden", + "common.time.hoursAgo.short": "{{count}}u geleden", + "common.time.daysAgo.short": "{{count}}d geleden", + + "sidebar.menu.toggle": "Menu in-/uitschakelen", + "sidebar.nav.projectsAndSessions": "Projecten en sessies", + "sidebar.settings": "Instellingen", + "sidebar.help": "Help", + "sidebar.workspaces.enable": "Werkruimtes inschakelen", + "sidebar.workspaces.disable": "Werkruimtes uitschakelen", + "sidebar.gettingStarted.title": "Aan de slag", + "sidebar.gettingStarted.line1": "Kilo bevat gratis modellen zodat u direct kunt beginnen.", + "sidebar.gettingStarted.line2": "Verbind een provider om modellen te gebruiken, incl. Claude, GPT, Gemini etc.", + "sidebar.project.recentSessions": "Recente sessies", + "sidebar.project.viewAllSessions": "Bekijk alle sessies", + "sidebar.project.clearNotifications": "Meldingen wissen", + + "app.name.desktop": "Kilo Desktop", + + "settings.section.desktop": "Desktop", + "settings.section.server": "Server", + "settings.tab.general": "Algemeen", + "settings.tab.shortcuts": "Sneltoetsen", + "settings.desktop.section.wsl": "WSL", + "settings.desktop.wsl.title": "WSL-integratie", + "settings.desktop.wsl.description": "Draai de Kilo server binnen WSL op Windows.", + + "settings.general.section.appearance": "Uiterlijk", + "settings.general.section.notifications": "Systeemmeldingen", + "settings.general.section.updates": "Updates", + "settings.general.section.sounds": "Geluidseffecten", + "settings.general.section.feed": "Feed", + "settings.general.section.display": "Weergave", + + "settings.general.row.language.title": "Taal", + "settings.general.row.language.description": "Wijzig de weergavetaal voor Kilo", + "settings.general.row.appearance.title": "Uiterlijk", + "settings.general.row.appearance.description": "Pas aan hoe Kilo eruitziet op uw apparaat", + "settings.general.row.theme.title": "Thema", + "settings.general.row.theme.description": "Pas het thema van Kilo aan.", + "settings.general.row.font.title": "Lettertype", + "settings.general.row.font.description": "Pas het monospace-lettertype in codeblokken aan", + "settings.general.row.reasoningSummaries.title": "Redeneersamenvattingen weergeven", + "settings.general.row.reasoningSummaries.description": "Toon model-redeneersamenvattingen in de tijdlijn", + "settings.general.row.shellToolPartsExpanded.title": "Shell-toolonderdelen uitklappen", + "settings.general.row.shellToolPartsExpanded.description": + "Toon shell-toolonderdelen standaard uitgeklapt in de tijdlijn", + "settings.general.row.editToolPartsExpanded.title": "Bewerk-toolonderdelen uitklappen", + "settings.general.row.editToolPartsExpanded.description": + "Toon bewerk-, schrijf- en patch-toolonderdelen standaard uitgeklapt in de tijdlijn", + + "settings.general.row.wayland.title": "Gebruik native Wayland", + "settings.general.row.wayland.description": "Schakel X11-terugval uit op Wayland. Vereist een herstart.", + "settings.general.row.wayland.tooltip": + "Op Linux met monitoren met gemengde verversingssnelheden kan native Wayland stabieler zijn.", + + "settings.general.row.releaseNotes.title": "Release notes", + "settings.general.row.releaseNotes.description": "Toon Wat is nieuw pop-ups na updates", + + "settings.updates.row.startup.title": "Controleren op updates bij opstarten", + "settings.updates.row.startup.description": "Automatisch op updates controleren wanneer Kilo start", + "settings.updates.row.check.title": "Controleren op updates", + "settings.updates.row.check.description": "Handmatig op updates controleren en installeren indien beschikbaar", + "settings.updates.action.checkNow": "Nu controleren", + "settings.updates.action.checking": "Controleren...", + "settings.updates.toast.latest.title": "U bent up-to-date", + "settings.updates.toast.latest.description": "U draait de nieuwste versie van Kilo.", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.iosevka": "Iosevka", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "font.option.geistMono": "Geist Mono", + "sound.option.none": "Geen", + "sound.option.alert01": "Melding 01", + "sound.option.alert02": "Melding 02", + "sound.option.alert03": "Melding 03", + "sound.option.alert04": "Melding 04", + "sound.option.alert05": "Melding 05", + "sound.option.alert06": "Melding 06", + "sound.option.alert07": "Melding 07", + "sound.option.alert08": "Melding 08", + "sound.option.alert09": "Melding 09", + "sound.option.alert10": "Melding 10", + "sound.option.bipbop01": "Bip-bop 01", + "sound.option.bipbop02": "Bip-bop 02", + "sound.option.bipbop03": "Bip-bop 03", + "sound.option.bipbop04": "Bip-bop 04", + "sound.option.bipbop05": "Bip-bop 05", + "sound.option.bipbop06": "Bip-bop 06", + "sound.option.bipbop07": "Bip-bop 07", + "sound.option.bipbop08": "Bip-bop 08", + "sound.option.bipbop09": "Bip-bop 09", + "sound.option.bipbop10": "Bip-bop 10", + "sound.option.staplebops01": "Staplebops 01", + "sound.option.staplebops02": "Staplebops 02", + "sound.option.staplebops03": "Staplebops 03", + "sound.option.staplebops04": "Staplebops 04", + "sound.option.staplebops05": "Staplebops 05", + "sound.option.staplebops06": "Staplebops 06", + "sound.option.staplebops07": "Staplebops 07", + "sound.option.nope01": "Nee 01", + "sound.option.nope02": "Nee 02", + "sound.option.nope03": "Nee 03", + "sound.option.nope04": "Nee 04", + "sound.option.nope05": "Nee 05", + "sound.option.nope06": "Nee 06", + "sound.option.nope07": "Nee 07", + "sound.option.nope08": "Nee 08", + "sound.option.nope09": "Nee 09", + "sound.option.nope10": "Nee 10", + "sound.option.nope11": "Nee 11", + "sound.option.nope12": "Nee 12", + "sound.option.yup01": "Ja 01", + "sound.option.yup02": "Ja 02", + "sound.option.yup03": "Ja 03", + "sound.option.yup04": "Ja 04", + "sound.option.yup05": "Ja 05", + "sound.option.yup06": "Ja 06", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Toon systeemmelding wanneer de agent klaar is of aandacht nodig heeft", + "settings.general.notifications.permissions.title": "Machtigingen", + "settings.general.notifications.permissions.description": "Toon systeemmelding wanneer een machtiging vereist is", + "settings.general.notifications.errors.title": "Fouten", + "settings.general.notifications.errors.description": "Toon systeemmelding wanneer er een fout optreedt", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Speel geluid af wanneer de agent klaar is of aandacht nodig heeft", + "settings.general.sounds.permissions.title": "Machtigingen", + "settings.general.sounds.permissions.description": "Speel geluid af wanneer een machtiging vereist is", + "settings.general.sounds.errors.title": "Fouten", + "settings.general.sounds.errors.description": "Speel geluid af wanneer er een fout optreedt", + + "settings.shortcuts.title": "Sneltoetsen", + "settings.shortcuts.reset.button": "Terugzetten naar standaard", + "settings.shortcuts.reset.toast.title": "Sneltoetsen gereset", + "settings.shortcuts.reset.toast.description": "Sneltoetsen zijn teruggezet naar de standaardwaarden.", + "settings.shortcuts.conflict.title": "Sneltoets al in gebruik", + "settings.shortcuts.conflict.description": "{{keybind}} is al toegewezen aan {{titles}}.", + "settings.shortcuts.unassigned": "Niet toegewezen", + "settings.shortcuts.pressKeys": "Druk op toetsen", + "settings.shortcuts.search.placeholder": "Zoek sneltoetsen", + "settings.shortcuts.search.empty": "Geen sneltoetsen gevonden", + + "settings.shortcuts.group.general": "Algemeen", + "settings.shortcuts.group.session": "Sessie", + "settings.shortcuts.group.navigation": "Navigatie", + "settings.shortcuts.group.modelAndAgent": "Model en agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Providers", + "settings.providers.description": "Provider-instellingen kunnen hier worden geconfigureerd.", + "settings.providers.section.connected": "Verbonden providers", + "settings.providers.connected.empty": "Geen verbonden providers", + "settings.providers.connected.environmentDescription": "Verbonden vanuit uw omgevingsvariabelen", + "settings.providers.section.popular": "Populaire providers", + "settings.providers.custom.description": "Voeg een OpenAI-compatibele provider toe via basis-URL.", + "settings.providers.tag.environment": "Omgeving", + "settings.providers.tag.config": "Config", + "settings.providers.tag.custom": "Aangepast", + "settings.providers.tag.other": "Overig", + "settings.models.title": "Modellen", + "settings.models.description": "Model-instellingen kunnen hier worden geconfigureerd.", + "settings.agents.title": "Agenten", + "settings.agents.description": "Agent-instellingen kunnen hier worden geconfigureerd.", + "settings.commands.title": "Opdrachten", + "settings.commands.description": "Opdracht-instellingen kunnen hier worden geconfigureerd.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP-instellingen kunnen hier worden geconfigureerd.", + + "settings.permissions.title": "Machtigingen", + "settings.permissions.description": "Bepaal welke tools de server standaard mag gebruiken.", + "settings.permissions.section.tools": "Tools", + "settings.permissions.toast.updateFailed.title": "Bijwerken van machtigingen mislukt", + + "settings.permissions.action.allow": "Toestaan", + "settings.permissions.action.ask": "Vragen", + "settings.permissions.action.deny": "Weigeren", + + "settings.permissions.tool.read.title": "Lezen (Read)", + "settings.permissions.tool.read.description": "Een bestand lezen (komt overeen met het bestandspad)", + "settings.permissions.tool.edit.title": "Bewerken (Edit)", + "settings.permissions.tool.edit.description": + "Bestanden wijzigen, inclusief bewerkingen, wegschrijven, patches en multi-edits", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Bestanden matchen met glob-patronen", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Bestandsinhoud doorzoeken met behulp van reguliere expressies", + "settings.permissions.tool.list.title": "Lijst (List)", + "settings.permissions.tool.list.description": "Bestanden in een map weergeven", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Shell-opdrachten uitvoeren", + "settings.permissions.tool.task.title": "Taak (Task)", + "settings.permissions.tool.task.description": "Sub-agenten lanceren", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "Een skill laden op naam", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Language server query's uitvoeren", + "settings.permissions.tool.todoread.title": "To-do lezen (Todo Read)", + "settings.permissions.tool.todoread.description": "De to-do lijst lezen", + "settings.permissions.tool.todowrite.title": "To-do schrijven (Todo Write)", + "settings.permissions.tool.todowrite.description": "De to-do lijst bijwerken", + "settings.permissions.tool.webfetch.title": "Web ophalen (Web Fetch)", + "settings.permissions.tool.webfetch.description": "Inhoud ophalen van een URL", + "settings.permissions.tool.websearch.title": "Web zoeken (Web Search)", + "settings.permissions.tool.websearch.description": "Het web doorzoeken", + "settings.permissions.tool.codesearch.title": "Code zoeken (Code Search)", + "settings.permissions.tool.codesearch.description": "Zoeken naar code op het web", + "settings.permissions.tool.external_directory.title": "Externe Map", + "settings.permissions.tool.external_directory.description": "Toegang tot bestanden buiten de projectmap", + "settings.permissions.tool.doom_loop.title": "Eindeloze Loop (Doom Loop)", + "settings.permissions.tool.doom_loop.description": "Gedetecteerde herhaalde tool-aanroepen met identieke invoer", + + "session.delete.failed.title": "Verwijderen van sessie mislukt", + "session.delete.title": "Sessie verwijderen", + "session.delete.confirm": 'Sessie "{{name}}" verwijderen?', + "session.delete.button": "Sessie verwijderen", + + "workspace.new": "Nieuwe werkruimte", + "workspace.type.local": "lokaal", + "workspace.type.sandbox": "sandbox", + "workspace.create.failed.title": "Maken van werkruimte mislukt", + "workspace.delete.failed.title": "Verwijderen van werkruimte mislukt", + "workspace.resetting.title": "Werkruimte resetten", + "workspace.resetting.description": "Dit kan een minuut duren.", + "workspace.reset.failed.title": "Resetten van werkruimte mislukt", + "workspace.reset.success.title": "Werkruimte gereset", + "workspace.reset.success.description": "Werkruimte komt nu overeen met de standaardbranch.", + "workspace.error.stillPreparing": "Werkruimte is nog aan het voorbereiden", + "workspace.status.checking": "Controleren op ongemergde wijzigingen...", + "workspace.status.error": "Kan git-status niet verifiëren.", + "workspace.status.clean": "Geen ongemergde wijzigingen gedetecteerd.", + "workspace.status.dirty": "Ongemergde wijzigingen gedetecteerd in deze werkruimte.", + "workspace.delete.title": "Werkruimte verwijderen", + "workspace.delete.confirm": 'Werkruimte "{{name}}" verwijderen?', + "workspace.delete.button": "Werkruimte verwijderen", + "workspace.reset.title": "Werkruimte resetten", + "workspace.reset.confirm": 'Werkruimte "{{name}}" resetten?', + "workspace.reset.button": "Werkruimte resetten", + "workspace.reset.archived.none": "Geen actieve sessies zullen worden gearchiveerd.", + "workspace.reset.archived.one": "1 sessie zal worden gearchiveerd.", + "workspace.reset.archived.many": "{{count}} sessies zullen worden gearchiveerd.", + "workspace.reset.note": "Dit zal de werkruimte resetten zodat deze overeenkomt met de standaardbranch.", +} diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 23d22090064..bd38d490f04 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -116,7 +116,6 @@ export const dict = { "dialog.model.empty": "Ingen modellresultater", "dialog.model.manage": "Administrer modeller", "dialog.model.manage.description": "Tilpass hvilke modeller som vises i modellvelgeren.", - "dialog.model.manage.provider.toggle": "Veksle alle {{provider}}-modeller", "dialog.model.unpaid.freeModels.title": "Gratis modeller levert av Kilo", "dialog.model.unpaid.addMore.title": "Legg til flere modeller fra populære leverandører", @@ -501,7 +500,6 @@ export const dict = { "session.review.loadingChanges": "Laster endringer...", "session.review.empty": "Ingen endringer i denne sesjonen ennå", "session.review.noChanges": "Ingen endringer", - "session.review.noVcs": "Ingen git VCS oppdaget, så øktendringer vil ikke bli oppdaget", "session.files.selectToOpen": "Velg en fil å åpne", "session.files.all": "Alle filer", @@ -518,11 +516,7 @@ export const dict = { "session.todo.collapse": "Skjul", "session.todo.expand": "Utvid", - "session.modeSwitch.switching": "Bytter til {{mode}}-modus…", - "session.modeSwitch.waiting": "Venter på at gjeldende oppgave er ferdig", - "session.modeSwitch.notAvailable": "Agent ikke tilgjengelig", - "session.modeSwitch.fallback": '"{{requested}}" ikke funnet, bruker "{{actual}}"', - + "session.new.title": "Bygg hva som helst", "session.new.worktree.main": "Hovedgren", "session.new.worktree.mainWithBranch": "Hovedgren ({{branch}})", "session.new.worktree.create": "Opprett nytt worktree", @@ -622,8 +616,6 @@ export const dict = { "settings.general.row.theme.description": "Tilpass hvordan Kilo er tematisert.", "settings.general.row.font.title": "Skrift", "settings.general.row.font.description": "Tilpass mono-skriften som brukes i kodeblokker", - "settings.general.row.reasoningSummaries.title": "Vis resonneringssammendrag", - "settings.general.row.reasoningSummaries.description": "Vis modellressonneringssammendrag i tidslinjen", "settings.general.row.shellToolPartsExpanded.title": "Utvid shell-verktøydeler", "settings.general.row.shellToolPartsExpanded.description": "Vis shell-verktøydeler utvidet som standard i tidslinjen", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index e441a6fa63f..a7d3a9c9932 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -458,6 +458,7 @@ export const dict = { "session.todo.title": "Zadania", "session.todo.collapse": "Zwiń", "session.todo.expand": "Rozwiń", + "session.new.title": "Zbuduj cokolwiek", "session.new.worktree.main": "Główna gałąź", "session.new.worktree.mainWithBranch": "Główna gałąź ({{branch}})", "session.new.worktree.create": "Utwórz nowe drzewo robocze", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index 7ad44cab232..82a2f60abd5 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -113,7 +113,6 @@ export const dict = { "dialog.model.empty": "Модели не найдены", "dialog.model.manage": "Управление моделями", "dialog.model.manage.description": "Настройте какие модели появляются в выборе модели", - "dialog.model.manage.provider.toggle": "Переключить все модели {{provider}}", "dialog.model.unpaid.freeModels.title": "Бесплатные модели от Kilo", "dialog.model.unpaid.addMore.title": "Добавьте больше моделей от популярных провайдеров", @@ -501,7 +500,6 @@ export const dict = { "session.review.loadingChanges": "Загрузка изменений...", "session.review.empty": "Изменений в этой сессии пока нет", "session.review.noChanges": "Нет изменений", - "session.review.noVcs": "Git VCS не обнаружен, поэтому изменения сеанса не будут отслеживаться", "session.files.selectToOpen": "Выберите файл, чтобы открыть", "session.files.all": "Все файлы", "session.files.binaryContent": "Двоичный файл (содержимое не может быть отображено)", @@ -516,11 +514,7 @@ export const dict = { "session.todo.collapse": "Свернуть", "session.todo.expand": "Развернуть", - "session.modeSwitch.switching": "Переключение в режим {{mode}}…", - "session.modeSwitch.waiting": "Ожидание завершения текущей задачи", - "session.modeSwitch.notAvailable": "Агент недоступен", - "session.modeSwitch.fallback": '"{{requested}}" не найден, используется "{{actual}}"', - + "session.new.title": "Создавайте что угодно", "session.new.worktree.main": "Основная ветка", "session.new.worktree.mainWithBranch": "Основная ветка ({{branch}})", "session.new.worktree.create": "Создать новый worktree", @@ -620,8 +614,6 @@ export const dict = { "settings.general.row.theme.description": "Настройте оформление Kilo.", "settings.general.row.font.title": "Шрифт", "settings.general.row.font.description": "Настройте моноширинный шрифт для блоков кода", - "settings.general.row.reasoningSummaries.title": "Показывать сводки рассуждений", - "settings.general.row.reasoningSummaries.description": "Отображать сводки рассуждений модели в хронологии", "settings.general.row.shellToolPartsExpanded.title": "Разворачивать элементы инструмента shell", "settings.general.row.shellToolPartsExpanded.description": diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 35321260cb0..3243b5d322b 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -113,7 +113,6 @@ export const dict = { "dialog.model.empty": "ไม่พบผลลัพธ์โมเดล", "dialog.model.manage": "จัดการโมเดล", "dialog.model.manage.description": "ปรับแต่งโมเดลที่จะปรากฏในตัวเลือกโมเดล", - "dialog.model.manage.provider.toggle": "สลับโมเดล {{provider}} ทั้งหมด", "dialog.model.unpaid.freeModels.title": "โมเดลฟรีที่จัดหาให้โดย Kilo", "dialog.model.unpaid.addMore.title": "เพิ่มโมเดลเพิ่มเติมจากผู้ให้บริการยอดนิยม", @@ -495,7 +494,6 @@ export const dict = { "session.review.loadingChanges": "กำลังโหลดการเปลี่ยนแปลง...", "session.review.empty": "ยังไม่มีการเปลี่ยนแปลงในเซสชันนี้", "session.review.noChanges": "ไม่มีการเปลี่ยนแปลง", - "session.review.noVcs": "ไม่พบ git VCS ดังนั้นจะไม่สามารถตรวจจับการเปลี่ยนแปลงของเซสชันได้", "session.files.selectToOpen": "เลือกไฟล์เพื่อเปิด", "session.files.all": "ไฟล์ทั้งหมด", @@ -512,11 +510,7 @@ export const dict = { "session.todo.collapse": "ย่อ", "session.todo.expand": "ขยาย", - "session.modeSwitch.switching": "กำลังสลับไปยังโหมด {{mode}}…", - "session.modeSwitch.waiting": "รอให้งานปัจจุบันเสร็จสมบูรณ์", - "session.modeSwitch.notAvailable": "ตัวแทนไม่พร้อมใช้งาน", - "session.modeSwitch.fallback": 'ไม่พบ "{{requested}}" กำลังใช้ "{{actual}}"', - + "session.new.title": "สร้างอะไรก็ได้", "session.new.worktree.main": "สาขาหลัก", "session.new.worktree.mainWithBranch": "สาขาหลัก ({{branch}})", "session.new.worktree.create": "สร้าง worktree ใหม่", @@ -613,8 +607,6 @@ export const dict = { "settings.general.row.theme.description": "ปรับแต่งวิธีการที่ Kilo มีธีม", "settings.general.row.font.title": "ฟอนต์", "settings.general.row.font.description": "ปรับแต่งฟอนต์โมโนที่ใช้ในบล็อกโค้ด", - "settings.general.row.reasoningSummaries.title": "แสดงสรุปการให้เหตุผล", - "settings.general.row.reasoningSummaries.description": "แสดงสรุปการให้เหตุผลของโมเดลในไทม์ไลน์", "settings.general.row.shellToolPartsExpanded.title": "ขยายส่วนเครื่องมือ shell", "settings.general.row.shellToolPartsExpanded.description": "แสดงส่วนเครื่องมือ shell แบบขยายตามค่าเริ่มต้นในไทม์ไลน์", diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index 242ce219217..762ab6f2330 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -522,6 +522,7 @@ export const dict = { "session.todo.collapse": "Daralt", "session.todo.expand": "Genişlet", + "session.new.title": "İstediğini yap", "session.new.worktree.main": "Ana dal", "session.new.worktree.mainWithBranch": "Ana dal ({{branch}})", "session.new.worktree.create": "Yeni çalışma ağacı oluştur", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 15abb8437fd..5f4a64cea96 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -510,6 +510,7 @@ export const dict = { "session.todo.title": "待办事项", "session.todo.collapse": "折叠", "session.todo.expand": "展开", + "session.new.title": "构建任何东西", "session.new.worktree.main": "主分支", "session.new.worktree.mainWithBranch": "主分支({{branch}})", "session.new.worktree.create": "创建新的 worktree", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 9959f501c40..c77f6fd52d8 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -117,7 +117,6 @@ export const dict = { "dialog.model.empty": "找不到模型", "dialog.model.manage": "管理模型", "dialog.model.manage.description": "自訂模型選擇器中顯示的模型。", - "dialog.model.manage.provider.toggle": "切換所有 {{provider}} 模型", "dialog.model.unpaid.freeModels.title": "Kilo 提供的免費模型", "dialog.model.unpaid.addMore.title": "從熱門提供者新增更多模型", @@ -493,7 +492,6 @@ export const dict = { "session.review.loadingChanges": "正在載入變更...", "session.review.empty": "此工作階段暫無變更", "session.review.noChanges": "沒有變更", - "session.review.noVcs": "未偵測到 git VCS,因此無法偵測到工作階段變更", "session.files.selectToOpen": "選取要開啟的檔案", "session.files.all": "所有檔案", "session.files.binaryContent": "二進位檔案(無法顯示內容)", @@ -508,11 +506,7 @@ export const dict = { "session.todo.collapse": "折疊", "session.todo.expand": "展開", - "session.modeSwitch.switching": "正在切換到 {{mode}} 模式…", - "session.modeSwitch.waiting": "等待目前任務完成", - "session.modeSwitch.notAvailable": "Agent 不可用", - "session.modeSwitch.fallback": '找不到 "{{requested}}",使用 "{{actual}}"', - + "session.new.title": "建構任何東西", "session.new.worktree.main": "主分支", "session.new.worktree.mainWithBranch": "主分支 ({{branch}})", "session.new.worktree.create": "建立新的 worktree", @@ -608,8 +602,6 @@ export const dict = { "settings.general.row.theme.description": "自訂 Kilo 的主題。", "settings.general.row.font.title": "字型", "settings.general.row.font.description": "自訂程式碼區塊使用的等寬字型", - "settings.general.row.reasoningSummaries.title": "顯示推理摘要", - "settings.general.row.reasoningSummaries.description": "在時間軸中顯示模型推理摘要", "settings.general.row.shellToolPartsExpanded.title": "展開 shell 工具區塊", "settings.general.row.shellToolPartsExpanded.description": "在時間軸中預設展開 shell 工具區塊", diff --git a/packages/app/src/index.css b/packages/app/src/index.css index f9103c2be16..9e231e2d285 100644 --- a/packages/app/src/index.css +++ b/packages/app/src/index.css @@ -1 +1,29 @@ -@import "@kilocode/kilo-ui/styles/tailwind"; /* kilocode_change */ +@import "@opencode-ai/ui/styles/tailwind"; + +@layer components { + [data-component="getting-started"] { + container-type: inline-size; + container-name: getting-started; + } + + [data-component="getting-started-actions"] { + display: flex; + flex-direction: column; + gap: 0.75rem; /* gap-3 */ + } + + [data-component="getting-started-actions"] > [data-component="button"] { + width: 100%; + } + + @container getting-started (min-width: 17rem) { + [data-component="getting-started-actions"] { + flex-direction: row; + align-items: center; + } + + [data-component="getting-started-actions"] > [data-component="button"] { + width: auto; + } + } +} diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx index 71b52180f2e..fdf321f2dc3 100644 --- a/packages/app/src/pages/directory-layout.tsx +++ b/packages/app/src/pages/directory-layout.tsx @@ -1,26 +1,27 @@ -import { createEffect, createMemo, Show, type ParentProps } from "solid-js" +import { batch, createEffect, createMemo, Show, type ParentProps } from "solid-js" import { createStore } from "solid-js/store" -import { useNavigate, useParams } from "@solidjs/router" +import { useLocation, useNavigate, useParams } from "@solidjs/router" import { SDKProvider } from "@/context/sdk" import { SyncProvider, useSync } from "@/context/sync" import { LocalProvider } from "@/context/local" +import { useGlobalSDK } from "@/context/global-sdk" import { DataProvider } from "@opencode-ai/ui/context" +import { base64Encode } from "@opencode-ai/util/encode" import { decode64 } from "@/utils/base64" import { showToast } from "@opencode-ai/ui/toast" import { useLanguage } from "@/context/language" - function DirectoryDataProvider(props: ParentProps<{ directory: string }>) { - const params = useParams() const navigate = useNavigate() const sync = useSync() + const slug = createMemo(() => base64Encode(props.directory)) return ( navigate(`/${params.dir}/session/${sessionID}`)} - onSessionHref={(sessionID: string) => `/${params.dir}/session/${sessionID}`} + onNavigateToSession={(sessionID: string) => navigate(`/${slug()}/session/${sessionID}`)} + onSessionHref={(sessionID: string) => `/${slug()}/session/${sessionID}`} > {props.children} @@ -30,31 +31,63 @@ function DirectoryDataProvider(props: ParentProps<{ directory: string }>) { export default function Layout(props: ParentProps) { const params = useParams() const navigate = useNavigate() + const location = useLocation() const language = useLanguage() - const [store, setStore] = createStore({ invalid: "" }) - const directory = createMemo(() => { - return decode64(params.dir) ?? "" - }) + const globalSDK = useGlobalSDK() + const directory = createMemo(() => decode64(params.dir) ?? "") + const [state, setState] = createStore({ invalid: "", resolved: "" }) createEffect(() => { if (!params.dir) return - if (directory()) return - if (store.invalid === params.dir) return - setStore("invalid", params.dir) - showToast({ - variant: "error", - title: language.t("common.requestFailed"), - description: language.t("directory.error.invalidUrl"), - }) - navigate("/", { replace: true }) + const raw = directory() + if (!raw) { + if (state.invalid === params.dir) return + setState("invalid", params.dir) + showToast({ + variant: "error", + title: language.t("common.requestFailed"), + description: language.t("directory.error.invalidUrl"), + }) + navigate("/", { replace: true }) + return + } + + const current = params.dir + globalSDK + .createClient({ + directory: raw, + throwOnError: true, + }) + .path.get() + .then((x) => { + if (params.dir !== current) return + const next = x.data?.directory ?? raw + batch(() => { + setState("invalid", "") + setState("resolved", next) + }) + if (next === raw) return + const path = location.pathname.slice(current.length + 1) + navigate(`/${base64Encode(next)}${path}${location.search}${location.hash}`, { replace: true }) + }) + .catch(() => { + if (params.dir !== current) return + batch(() => { + setState("invalid", "") + setState("resolved", raw) + }) + }) }) + return ( - - - - {props.children} - - + + {(resolved) => ( + + + {props.children} + + + )} ) } diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 53e545db496..7b70b53b984 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -10,9 +10,8 @@ import { ParentProps, Show, untrack, - type JSX, } from "solid-js" -import { A, useNavigate, useParams } from "@solidjs/router" +import { useNavigate, useParams } from "@solidjs/router" import { useLayout, LocalProject } from "@/context/layout" import { useGlobalSync } from "@/context/global-sync" import { Persist, persisted } from "@/utils/persist" @@ -20,9 +19,8 @@ import { base64Encode } from "@opencode-ai/util/encode" import { decode64 } from "@/utils/base64" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Button } from "@opencode-ai/ui/button" -import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" -import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { Dialog } from "@opencode-ai/ui/dialog" import { getFilename } from "@opencode-ai/util/path" @@ -36,6 +34,7 @@ import { useProviders } from "@/hooks/use-providers" import { showToast, Toast, toaster } from "@opencode-ai/ui/toast" import { useGlobalSDK } from "@/context/global-sdk" import { clearWorkspaceTerminals } from "@/context/terminal" +import { dropSessionCaches, pickSessionCacheEvictions } from "@/context/global-sync/session-cache" import { useNotification } from "@/context/notification" import { usePermission } from "@/context/permission" import { Binary } from "@opencode-ai/util/binary" @@ -44,6 +43,7 @@ import { playSound, soundSrc } from "@/utils/sound" import { createAim } from "@/utils/aim" import { setNavigate } from "@/utils/notification-click" import { Worktree as WorktreeState } from "@/utils/worktree" +import { setSessionHandoff } from "@/pages/session/handoff" import { useDialog } from "@opencode-ai/ui/context/dialog" import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme" @@ -58,7 +58,6 @@ import { Titlebar } from "@/components/titlebar" import { useServer } from "@/context/server" import { useLanguage, type Locale } from "@/context/language" import { - childMapByParent, displayName, effectiveWorkspaceOrder, errorMessage, @@ -67,7 +66,12 @@ import { sortedRootSessions, workspaceKey, } from "./layout/helpers" -import { collectOpenProjectDeepLinks, deepLinkEvent, drainPendingDeepLinks } from "./layout/deep-links" +import { + collectNewSessionDeepLinks, + collectOpenProjectDeepLinks, + deepLinkEvent, + drainPendingDeepLinks, +} from "./layout/deep-links" import { createInlineEditorController } from "./layout/inline-editor" import { LocalWorkspace, @@ -90,6 +94,7 @@ export default function Layout(props: ParentProps) { workspaceName: {} as Record, workspaceBranchName: {} as Record>, workspaceExpanded: {} as Record, + gettingStartedDismissed: false, }), ) @@ -151,6 +156,8 @@ export default function Layout(props: ParentProps) { const isBusy = (directory: string) => !!state.busyWorkspaces[workspaceKey(directory)] const navLeave = { current: undefined as number | undefined } const [sortNow, setSortNow] = createSignal(Date.now()) + const [sizing, setSizing] = createSignal(false) + let sizet: number | undefined let sortNowInterval: ReturnType | undefined const sortNowTimeout = setTimeout( () => { @@ -163,7 +170,7 @@ export default function Layout(props: ParentProps) { const aim = createAim({ enabled: () => !layout.sidebar.opened(), active: () => state.hoverProject, - el: () => state.nav, + el: () => state.nav?.querySelector("[data-component='sidebar-rail']") ?? state.nav, onActivate: (directory) => { globalSync.child(directory) setState("hoverProject", directory) @@ -175,9 +182,23 @@ export default function Layout(props: ParentProps) { if (navLeave.current !== undefined) clearTimeout(navLeave.current) clearTimeout(sortNowTimeout) if (sortNowInterval) clearInterval(sortNowInterval) + if (sizet !== undefined) clearTimeout(sizet) + if (peekt !== undefined) clearTimeout(peekt) aim.reset() }) + onMount(() => { + const stop = () => setSizing(false) + window.addEventListener("pointerup", stop) + window.addEventListener("pointercancel", stop) + window.addEventListener("blur", stop) + onCleanup(() => { + window.removeEventListener("pointerup", stop) + window.removeEventListener("pointercancel", stop) + window.removeEventListener("blur", stop) + }) + }) + const sidebarHovering = createMemo(() => !layout.sidebar.opened() && state.hoverProject !== undefined) const sidebarExpanded = createMemo(() => layout.sidebar.opened() || sidebarHovering()) const setHoverProject = (value: string | undefined) => { @@ -188,12 +209,54 @@ export default function Layout(props: ParentProps) { const clearHoverProjectSoon = () => queueMicrotask(() => setHoverProject(undefined)) const setHoverSession = (id: string | undefined) => setState("hoverSession", id) + const disarm = () => { + if (navLeave.current === undefined) return + clearTimeout(navLeave.current) + navLeave.current = undefined + } + + const arm = () => { + if (layout.sidebar.opened()) return + if (state.hoverProject === undefined) return + disarm() + navLeave.current = window.setTimeout(() => { + navLeave.current = undefined + setHoverProject(undefined) + setState("hoverSession", undefined) + }, 300) + } + + const [peek, setPeek] = createSignal(undefined) + const [peeked, setPeeked] = createSignal(false) + let peekt: number | undefined + const hoverProjectData = createMemo(() => { const id = state.hoverProject if (!id) return return layout.projects.list().find((project) => project.worktree === id) }) + createEffect(() => { + const p = hoverProjectData() + if (p) { + if (peekt !== undefined) { + clearTimeout(peekt) + peekt = undefined + } + setPeek(p) + setPeeked(true) + return + } + + setPeeked(false) + if (peek() === undefined) return + if (peekt !== undefined) clearTimeout(peekt) + peekt = window.setTimeout(() => { + peekt = undefined + setPeek(undefined) + }, 180) + }) + createEffect(() => { if (!layout.sidebar.opened()) return setHoverProject(undefined) @@ -361,6 +424,17 @@ export default function Layout(props: ParentProps) { return } + if ( + e.details?.type === "question.replied" || + e.details?.type === "question.rejected" || + e.details?.type === "permission.replied" + ) { + const props = e.details.properties as { sessionID: string } + const sessionKey = `${e.name}:${props.sessionID}` + dismissSessionAlert(sessionKey) + return + } + if (e.details?.type !== "permission.asked" && e.details?.type !== "question.asked") return const title = e.details.type === "permission.asked" @@ -595,25 +669,24 @@ export default function Layout(props: ParentProps) { const prefetchQueues = new Map() const PREFETCH_MAX_SESSIONS_PER_DIR = 10 - const prefetchedByDir = new Map>() + const prefetchedByDir = new Map>() const lruFor = (directory: string) => { const existing = prefetchedByDir.get(directory) if (existing) return existing - const created = new Map() + const created = new Set() prefetchedByDir.set(directory, created) return created } const markPrefetched = (directory: string, sessionID: string) => { const lru = lruFor(directory) - if (lru.has(sessionID)) lru.delete(sessionID) - lru.set(sessionID, true) - while (lru.size > PREFETCH_MAX_SESSIONS_PER_DIR) { - const oldest = lru.keys().next().value as string | undefined - if (!oldest) return - lru.delete(oldest) - } + return pickSessionCacheEvictions({ + seen: lru, + keep: sessionID, + limit: PREFETCH_MAX_SESSIONS_PER_DIR, + preserve: directory === params.dir && params.id ? [params.id] : undefined, + }) } createEffect(() => { @@ -662,6 +735,7 @@ export default function Layout(props: ParentProps) { return retry(() => globalSDK.client.session.messages({ directory, sessionID, limit: prefetchChunk })) .then((messages) => { if (prefetchToken.value !== token) return + if (!lruFor(directory).has(sessionID)) return const items = (messages.data ?? []).filter((x) => !!x?.info?.id) const next = items.map((x) => x.info).filter((m): m is Message => !!m?.id) @@ -725,7 +799,18 @@ export default function Layout(props: ParentProps) { const lru = lruFor(directory) const known = lru.has(session.id) if (!known && lru.size >= PREFETCH_MAX_SESSIONS_PER_DIR && priority !== "high") return - markPrefetched(directory, session.id) + const stale = markPrefetched(directory, session.id) + if (stale.length > 0) { + const [, setStore] = globalSync.child(directory, { bootstrap: false }) + for (const id of stale) { + globalSync.todo.set(id, undefined) + } + setStore( + produce((draft) => { + dropSessionCaches(draft, stale) + }), + ) + } if (priority === "high") q.pending.unshift(session.id) if (priority !== "high") q.pending.push(session.id) @@ -1041,18 +1126,13 @@ export default function Layout(props: ParentProps) { } function projectRoot(directory: string) { - const key = workspaceKey(directory) const project = layout.projects .list() - .find( - (item) => - workspaceKey(item.worktree) === key || - (item.sandboxes ?? []).some((sandbox) => workspaceKey(sandbox) === key), - ) + .find((item) => item.worktree === directory || item.sandboxes?.includes(directory)) if (project) return project.worktree const known = Object.entries(store.workspaceOrder).find( - ([root, dirs]) => workspaceKey(root) === key || dirs.some((dir) => workspaceKey(dir) === key), + ([root, dirs]) => root === directory || dirs.includes(directory), ) if (known) return known[0] @@ -1124,6 +1204,12 @@ export default function Layout(props: ParentProps) { } const openSession = async (target: { directory: string; id: string }) => { if (!canOpen(target.directory)) return false + const [data] = globalSync.child(target.directory, { bootstrap: false }) + if (data.session.some((item) => item.id === target.id)) { + setStore("lastProjectSession", root, { directory: target.directory, id: target.id, at: Date.now() }) + navigateWithSidebarReset(`/${base64Encode(target.directory)}/session/${target.id}`) + return true + } const resolved = await globalSDK.client.session .get({ sessionID: target.id }) .then((x) => x.data) @@ -1182,9 +1268,20 @@ export default function Layout(props: ParentProps) { const handleDeepLinks = (urls: string[]) => { if (!server.isLocal()) return + for (const directory of collectOpenProjectDeepLinks(urls)) { openProject(directory) } + + for (const link of collectNewSessionDeepLinks(urls)) { + openProject(link.directory, false) + const slug = base64Encode(link.directory) + if (link.prompt) { + setSessionHandoff(slug, { prompt: link.prompt }) + } + const href = link.prompt ? `/${slug}/session?prompt=${encodeURIComponent(link.prompt)}` : `/${slug}/session` + navigateWithSidebarReset(href) + } } onMount(() => { @@ -1803,7 +1900,9 @@ export default function Layout(props: ParentProps) { setHoverSession, } - const SidebarPanel = (panelProps: { project: LocalProject | undefined; mobile?: boolean }) => { + const SidebarPanel = (panelProps: { project: LocalProject | undefined; mobile?: boolean; merged?: boolean }) => { + const merged = createMemo(() => panelProps.mobile || (panelProps.merged ?? layout.sidebar.opened())) + const hover = createMemo(() => !panelProps.mobile && panelProps.merged === false && !layout.sidebar.opened()) const projectName = createMemo(() => { const project = panelProps.project if (!project) return "" @@ -1829,10 +1928,17 @@ export default function Layout(props: ParentProps) { return (
{(p) => ( @@ -1878,7 +1984,7 @@ export default function Layout(props: ParentProps) { }} aria-label={language.t("common.moreOptions")} /> - + showEditProjectDialog(p())}> {language.t("common.edit")} @@ -1925,20 +2031,14 @@ export default function Layout(props: ParentProps) { fallback={ <>
- navigateWithSidebarReset(`/${base64Encode(p().worktree)}/session`)} > - - + {language.t("command.session.new")} +
<>
- - - +
0 && providers.paid().length === 0), + hidden: store.gettingStartedDismissed || !(providers.all().length > 0 && providers.paid().length === 0), }} > -
-
-
{language.t("sidebar.gettingStarted.title")}
-
{language.t("sidebar.gettingStarted.line1")}
-
{language.t("sidebar.gettingStarted.line2")}
+
+
+
+
{language.t("sidebar.gettingStarted.title")}
+
+ {language.t("sidebar.gettingStarted.line1")} +
+
+ {language.t("sidebar.gettingStarted.line2")} +
+
+
+ + +
-
@@ -2037,33 +2137,27 @@ export default function Layout(props: ParentProps) { return (
-
+
+ + diff --git a/packages/app/src/pages/layout/deep-links.ts b/packages/app/src/pages/layout/deep-links.ts index ecbad271fc2..67137f17fa9 100644 --- a/packages/app/src/pages/layout/deep-links.ts +++ b/packages/app/src/pages/layout/deep-links.ts @@ -1,15 +1,17 @@ export const deepLinkEvent = "opencode:deep-link" -export const parseDeepLink = (input: string) => { +const parseUrl = (input: string) => { if (!input.startsWith("opencode://")) return if (typeof URL.canParse === "function" && !URL.canParse(input)) return - const url = (() => { - try { - return new URL(input) - } catch { - return undefined - } - })() + try { + return new URL(input) + } catch { + return + } +} + +export const parseDeepLink = (input: string) => { + const url = parseUrl(input) if (!url) return if (url.hostname !== "open-project") return const directory = url.searchParams.get("directory") @@ -17,9 +19,23 @@ export const parseDeepLink = (input: string) => { return directory } +export const parseNewSessionDeepLink = (input: string) => { + const url = parseUrl(input) + if (!url) return + if (url.hostname !== "new-session") return + const directory = url.searchParams.get("directory") + if (!directory) return + const prompt = url.searchParams.get("prompt") || undefined + if (!prompt) return { directory } + return { directory, prompt } +} + export const collectOpenProjectDeepLinks = (urls: string[]) => urls.map(parseDeepLink).filter((directory): directory is string => !!directory) +export const collectNewSessionDeepLinks = (urls: string[]) => + urls.map(parseNewSessionDeepLink).filter((link): link is { directory: string; prompt?: string } => !!link) + type OpenCodeWindow = Window & { __KILO__?: { deepLinks?: string[] diff --git a/packages/app/src/pages/layout/helpers.test.ts b/packages/app/src/pages/layout/helpers.test.ts index 4f82198595f..bd2d60bbd57 100644 --- a/packages/app/src/pages/layout/helpers.test.ts +++ b/packages/app/src/pages/layout/helpers.test.ts @@ -1,15 +1,14 @@ import { describe, expect, test } from "bun:test" -import { type Session } from "@kilocode/sdk/v2/client" -import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links" import { - displayName, - errorMessage, - getDraggableId, - hasProjectPermissions, - latestRootSession, - syncWorkspaceOrder, - workspaceKey, -} from "./helpers" + collectNewSessionDeepLinks, + collectOpenProjectDeepLinks, + drainPendingDeepLinks, + parseDeepLink, + parseNewSessionDeepLink, +} from "./deep-links" +import { displayName, errorMessage, getDraggableId, syncWorkspaceOrder, workspaceKey } from "./helpers" +import { type Session } from "@kilocode/sdk/v2/client" +import { hasProjectPermissions, latestRootSession } from "./helpers" const session = (input: Partial & Pick) => ({ @@ -62,6 +61,28 @@ describe("layout deep links", () => { expect(result).toEqual(["/a", "/c"]) }) + test("parses new-session deep links with optional prompt", () => { + expect(parseNewSessionDeepLink("opencode://new-session?directory=/tmp/demo")).toEqual({ directory: "/tmp/demo" }) + expect(parseNewSessionDeepLink("opencode://new-session?directory=/tmp/demo&prompt=hello%20world")).toEqual({ + directory: "/tmp/demo", + prompt: "hello world", + }) + }) + + test("ignores new-session deep links without directory", () => { + expect(parseNewSessionDeepLink("opencode://new-session")).toBeUndefined() + expect(parseNewSessionDeepLink("opencode://new-session?directory=")).toBeUndefined() + }) + + test("collects only valid new-session deep links", () => { + const result = collectNewSessionDeepLinks([ + "opencode://new-session?directory=/a", + "opencode://open-project?directory=/b", + "opencode://new-session?directory=/c&prompt=ship%20it", + ]) + expect(result).toEqual([{ directory: "/a" }, { directory: "/c", prompt: "ship it" }]) + }) + test("drains global deep links once", () => { const target = { __KILO__: { diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index d2d83cd69c7..9160ca397be 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -1,10 +1,4 @@ -import { A, useNavigate, useParams } from "@solidjs/router" -import { useGlobalSync } from "@/context/global-sync" -import { useLanguage } from "@/context/language" -import { useLayout, type LocalProject, getAvatarColors } from "@/context/layout" -import { useNotification } from "@/context/notification" -import { usePermission } from "@/context/permission" -import { base64Encode } from "@opencode-ai/util/encode" +import type { Message, Session, TextPart, UserMessage } from "@kilocode/sdk/v2/client" import { Avatar } from "@opencode-ai/ui/avatar" import { HoverCard } from "@opencode-ai/ui/hover-card" import { Icon } from "@opencode-ai/ui/icon" @@ -12,12 +6,18 @@ import { IconButton } from "@opencode-ai/ui/icon-button" import { MessageNav } from "@opencode-ai/ui/message-nav" import { Spinner } from "@opencode-ai/ui/spinner" import { Tooltip } from "@opencode-ai/ui/tooltip" +import { base64Encode } from "@opencode-ai/util/encode" import { getFilename } from "@opencode-ai/util/path" -import { type Message, type Session, type TextPart, type UserMessage } from "@kilocode/sdk/v2/client" -import { For, Match, Show, Switch, createMemo, onCleanup, type Accessor, type JSX } from "solid-js" +import { A, useNavigate, useParams } from "@solidjs/router" +import { type Accessor, createMemo, For, type JSX, Match, onCleanup, Show, Switch } from "solid-js" +import { useGlobalSync } from "@/context/global-sync" +import { useLanguage } from "@/context/language" +import { getAvatarColors, type LocalProject, useLayout } from "@/context/layout" +import { useNotification } from "@/context/notification" +import { usePermission } from "@/context/permission" import { agentColor } from "@/utils/agent" -import { hasProjectPermissions } from "./helpers" import { sessionPermissionRequest } from "../session/composer/session-request-tree" +import { hasProjectPermissions } from "./helpers" const KILO_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750" @@ -161,7 +161,6 @@ const SessionHoverPreview = (props: { gutter={16} shift={-2} trigger={props.trigger} - mount={!props.mobile ? props.nav() : undefined} open={props.hoverSession() === props.session.id} onOpenChange={(open) => props.setHoverSession(open ? props.session.id : undefined)} > @@ -229,7 +228,9 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { const hoverEnabled = createMemo(() => (props.popover ?? true) && hoverAllowed()) const isActive = createMemo(() => props.session.id === params.id) - const hoverPrefetch = { current: undefined as ReturnType | undefined } + const hoverPrefetch = { + current: undefined as ReturnType | undefined, + } const cancelHoverPrefetch = () => { if (hoverPrefetch.current === undefined) return clearTimeout(hoverPrefetch.current) @@ -298,17 +299,15 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { setHoverSession={props.setHoverSession} messageLabel={messageLabel} onMessageSelect={(message) => { - if (!isActive()) { + if (!isActive()) layout.pendingMessage.set(`${base64Encode(props.session.directory)}/${props.session.id}`, message.id) - navigate(`${props.slug}/session/${props.session.id}`) - return - } - window.history.replaceState(null, "", `#message-${message.id}`) - window.dispatchEvent(new HashChangeEvent("hashchange")) + + navigate(`${props.slug}/session/${props.session.id}#message-${message.id}`) }} trigger={item} /> +
{ props.setMenu(value) + props.setSuppressHover(value) if (value) props.setOpen(false) }} > @@ -109,6 +108,12 @@ const ProjectTile = (props: { !props.selected() && !props.active(), "bg-surface-base-hover border border-border-weak-base": !props.selected() && props.active(), }} + onPointerDown={(event) => { + if (!props.overlay()) return + if (event.button !== 2 && !(event.button === 0 && event.ctrlKey)) return + props.setSuppressHover(true) + event.preventDefault() + }} onMouseEnter={(event: MouseEvent) => { if (!props.overlay()) return if (props.suppressHover()) return @@ -137,7 +142,7 @@ const ProjectTile = (props: { > - + props.showEditProjectDialog(props.project)}> {props.language.t("common.edit")} @@ -194,21 +199,6 @@ const ProjectPreviewPanel = (props: {
{displayName(props.project)}
- - { - event.stopPropagation() - props.setOpen(false) - props.ctx.closeProject(props.project.worktree) - }} - /> -
{props.language.t("sidebar.project.recentSessions")}
diff --git a/packages/app/src/pages/layout/sidebar-shell.tsx b/packages/app/src/pages/layout/sidebar-shell.tsx index d813ef3e116..d3070e37491 100644 --- a/packages/app/src/pages/layout/sidebar-shell.tsx +++ b/packages/app/src/pages/layout/sidebar-shell.tsx @@ -1,4 +1,4 @@ -import { createMemo, For, Show, type Accessor, type JSX } from "solid-js" +import { createEffect, createMemo, For, Show, type Accessor, type JSX } from "solid-js" import { DragDropProvider, DragDropSensors, @@ -35,10 +35,22 @@ export const SidebarContent = (props: { }): JSX.Element => { const expanded = createMemo(() => sidebarExpanded(props.mobile, props.opened())) const placement = () => (props.mobile ? "bottom" : "right") + let panel: HTMLDivElement | undefined + + createEffect(() => { + const el = panel + if (!el) return + if (expanded()) { + el.removeAttribute("inert") + return + } + el.setAttribute("inert", "") + }) return ( -
+
@@ -100,7 +112,15 @@ export const SidebarContent = (props: {
- {props.renderPanel()} +
{ + panel = el + }} + classList={{ "flex h-full min-h-0 min-w-0 overflow-hidden": true, "pointer-events-none": !expanded() }} + aria-hidden={!expanded()} + > + {props.renderPanel()} +
) } diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx index 42d16830813..2529a999ae4 100644 --- a/packages/app/src/pages/layout/sidebar-workspace.tsx +++ b/packages/app/src/pages/layout/sidebar-workspace.tsx @@ -182,7 +182,7 @@ const WorkspaceActions = (props: { aria-label={props.language.t("common.moreOptions")} /> - + { if (!props.pendingRename()) return @@ -249,7 +249,7 @@ const WorkspaceSessionList = (props: { loadMore: () => Promise language: ReturnType }): JSX.Element => ( -
@@ -1051,23 +1192,6 @@ export default function Page() { tabs().setActive(next) }) - createEffect( - on( - () => layout.fileTree.opened(), - (opened, prev) => { - if (prev === undefined) return - if (!isDesktop()) return - - if (opened) { - const active = tabs().active() - const tab = active === "review" || (!active && hasReview()) ? "changes" : "all" - layout.fileTree.setTab(tab) - } - }, - { defer: true }, - ), - ) - createEffect(() => { const id = params.id if (!id) return @@ -1118,12 +1242,6 @@ export default function Page() { let scrollStateFrame: number | undefined let scrollStateTarget: HTMLDivElement | undefined - const scrollSpy = createScrollSpy({ - onActive: (id) => { - if (id === store.messageId) return - setStore("messageId", id) - }, - }) const updateScrollState = (el: HTMLDivElement) => { const max = el.scrollHeight - el.clientHeight @@ -1171,31 +1289,21 @@ export default function Page() { ), ) - createEffect( - on( - sessionKey, - () => { - scrollSpy.clear() - }, - { defer: true }, - ), - ) - - const anchor = (id: string) => `message-${id}` - const setScrollRef = (el: HTMLDivElement | undefined) => { scroller = el autoScroll.scrollRef(el) - scrollSpy.setContainer(el) if (el) scheduleScrollState(el) } + const markUserScroll = () => { + scrollMark += 1 + } + createResizeObserver( () => content, () => { const el = scroller if (el) scheduleScrollState(el) - scrollSpy.markDirty() }, ) @@ -1228,7 +1336,6 @@ export default function Page() { if (stick) autoScroll.forceScrollToBottom() if (el) scheduleScrollState(el) - scrollSpy.markDirty() }, ) @@ -1256,7 +1363,7 @@ export default function Page() { onCleanup(() => { document.removeEventListener("keydown", handleKeyDown) - scrollSpy.destroy() + if (reviewFrame !== undefined) cancelAnimationFrame(reviewFrame) if (scrollStateFrame !== undefined) cancelAnimationFrame(scrollStateFrame) }) @@ -1276,9 +1383,9 @@ export default function Page() { {/* Session panel */}
- + @@ -1375,17 +1479,28 @@ export default function Page() { /> - +
size.start()}> + { + size.touch() + layout.session.resize(width) + }} + /> +
- +
diff --git a/packages/app/src/pages/session/composer/session-question-dock.tsx b/packages/app/src/pages/session/composer/session-question-dock.tsx index d64092cfe08..db1f788940e 100644 --- a/packages/app/src/pages/session/composer/session-question-dock.tsx +++ b/packages/app/src/pages/session/composer/session-question-dock.tsx @@ -8,6 +8,8 @@ import type { QuestionAnswer, QuestionRequest } from "@kilocode/sdk/v2" import { useLanguage } from "@/context/language" import { useSDK } from "@/context/sdk" +const cache = new Map() + // kilocode_change start - add onModeAction prop for mode-switching support export const SessionQuestionDock: Component<{ request: QuestionRequest @@ -21,16 +23,18 @@ export const SessionQuestionDock: Component<{ const questions = createMemo(() => props.request.questions) const total = createMemo(() => questions().length) + const cached = cache.get(props.request.id) const [store, setStore] = createStore({ - tab: 0, - answers: [] as QuestionAnswer[], - custom: [] as string[], - customOn: [] as boolean[], + tab: cached?.tab ?? 0, + answers: cached?.answers ?? ([] as QuestionAnswer[]), + custom: cached?.custom ?? ([] as string[]), + customOn: cached?.customOn ?? ([] as boolean[]), editing: false, sending: false, }) let root: HTMLDivElement | undefined + let replied = false const question = createMemo(() => questions()[store.tab]) const options = createMemo(() => question()?.options ?? []) @@ -113,6 +117,16 @@ export const SessionQuestionDock: Component<{ }) }) + onCleanup(() => { + if (replied) return + cache.set(props.request.id, { + tab: store.tab, + answers: store.answers.map((a) => (a ? [...a] : [])), + custom: store.custom.map((s) => s ?? ""), + customOn: store.customOn.map((b) => b ?? false), + }) + }) + const fail = (err: unknown) => { const message = err instanceof Error ? err.message : String(err) showToast({ title: language.t("common.requestFailed"), description: message }) @@ -125,6 +139,8 @@ export const SessionQuestionDock: Component<{ setStore("sending", true) try { await sdk.client.question.reply({ requestID: props.request.id, answers }) + replied = true + cache.delete(props.request.id) } catch (err) { fail(err) } finally { @@ -139,6 +155,8 @@ export const SessionQuestionDock: Component<{ setStore("sending", true) try { await sdk.client.question.reject({ requestID: props.request.id }) + replied = true + cache.delete(props.request.id) } catch (err) { fail(err) } finally { diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx index 93264353bd4..77643789d04 100644 --- a/packages/app/src/pages/session/file-tabs.tsx +++ b/packages/app/src/pages/session/file-tabs.tsx @@ -234,7 +234,6 @@ export function FileTabContent(props: { tab: string }) { if (typeof window === "undefined") return const onKeyDown = (event: KeyboardEvent) => { - if (event.defaultPrevented) return if (tabs().active() !== props.tab) return if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) return if (event.key.toLowerCase() !== "f") return diff --git a/packages/app/src/pages/session/helpers.test.ts b/packages/app/src/pages/session/helpers.test.ts index aaa5b932fe9..9c77c34af4e 100644 --- a/packages/app/src/pages/session/helpers.test.ts +++ b/packages/app/src/pages/session/helpers.test.ts @@ -11,12 +11,13 @@ describe("createOpenReviewFile", () => { return `file://${path}` }, openTab: (tab) => calls.push(`open:${tab}`), + setActive: (tab) => calls.push(`active:${tab}`), loadFile: (path) => calls.push(`load:${path}`), }) openReviewFile("src/a.ts") - expect(calls).toEqual(["show", "load:src/a.ts", "tab:src/a.ts", "open:file://src/a.ts"]) + expect(calls).toEqual(["show", "load:src/a.ts", "tab:src/a.ts", "open:file://src/a.ts", "active:file://src/a.ts"]) }) }) diff --git a/packages/app/src/pages/session/helpers.ts b/packages/app/src/pages/session/helpers.ts index 20f1d99a8be..be9656900d3 100644 --- a/packages/app/src/pages/session/helpers.ts +++ b/packages/app/src/pages/session/helpers.ts @@ -1,4 +1,5 @@ -import { batch } from "solid-js" +import { batch, createEffect, on, onCleanup, onMount, type Accessor } from "solid-js" +import { createStore } from "solid-js/store" export const focusTerminalById = (id: string) => { const wrapper = document.getElementById(`terminal-wrapper-${id}`) @@ -24,15 +25,20 @@ export const createOpenReviewFile = (input: { showAllFiles: () => void tabForPath: (path: string) => string openTab: (tab: string) => void + setActive: (tab: string) => void loadFile: (path: string) => any | Promise }) => { return (path: string) => { batch(() => { input.showAllFiles() const maybePromise = input.loadFile(path) - const openTab = () => input.openTab(input.tabForPath(path)) - if (maybePromise instanceof Promise) maybePromise.then(openTab) - else openTab() + const open = () => { + const tab = input.tabForPath(path) + input.openTab(tab) + input.setActive(tab) + } + if (maybePromise instanceof Promise) maybePromise.then(open) + else open() }) } } @@ -64,3 +70,104 @@ export const getTabReorderIndex = (tabs: readonly string[], from: string, to: st if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return undefined return toIndex } + +export const createSizing = () => { + const [state, setState] = createStore({ active: false }) + let t: number | undefined + + const stop = () => { + if (t !== undefined) { + clearTimeout(t) + t = undefined + } + setState("active", false) + } + + const start = () => { + if (t !== undefined) { + clearTimeout(t) + t = undefined + } + setState("active", true) + } + + onMount(() => { + window.addEventListener("pointerup", stop) + window.addEventListener("pointercancel", stop) + window.addEventListener("blur", stop) + onCleanup(() => { + window.removeEventListener("pointerup", stop) + window.removeEventListener("pointercancel", stop) + window.removeEventListener("blur", stop) + }) + }) + + onCleanup(() => { + if (t !== undefined) clearTimeout(t) + }) + + return { + active: () => state.active, + start, + touch() { + start() + t = window.setTimeout(stop, 120) + }, + } +} + +export type Sizing = ReturnType + +export const createPresence = (open: Accessor, wait = 200) => { + const [state, setState] = createStore({ + show: open(), + open: open(), + }) + let frame: number | undefined + let t: number | undefined + + const clear = () => { + if (frame !== undefined) { + cancelAnimationFrame(frame) + frame = undefined + } + if (t !== undefined) { + clearTimeout(t) + t = undefined + } + } + + createEffect( + on(open, (next) => { + clear() + + if (next) { + if (state.show) { + setState("open", true) + return + } + + setState({ show: true, open: false }) + frame = requestAnimationFrame(() => { + frame = undefined + setState("open", true) + }) + return + } + + if (!state.show) return + setState("open", false) + t = window.setTimeout(() => { + t = undefined + setState("show", false) + }, wait) + }), + ) + + onCleanup(clear) + + return { + show: () => state.show, + open: () => state.open, + } +} diff --git a/packages/app/src/pages/session/message-id-from-hash.ts b/packages/app/src/pages/session/message-id-from-hash.ts new file mode 100644 index 00000000000..2857f4b01d6 --- /dev/null +++ b/packages/app/src/pages/session/message-id-from-hash.ts @@ -0,0 +1,6 @@ +export const messageIdFromHash = (hash: string) => { + const value = hash.startsWith("#") ? hash.slice(1) : hash + const match = value.match(/^message-(.+)$/) + if (!match) return + return match[1] +} diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index a083d044485..f1092637ba1 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -1,4 +1,4 @@ -import { For, createEffect, createMemo, on, onCleanup, Show, startTransition, Index, type JSX } from "solid-js" +import { For, createEffect, createMemo, on, onCleanup, Show, Index, type JSX } from "solid-js" import { createStore, produce } from "solid-js/store" import { useNavigate, useParams } from "@solidjs/router" import { Button } from "@opencode-ai/ui/button" @@ -8,6 +8,7 @@ import { IconButton } from "@opencode-ai/ui/icon-button" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { Dialog } from "@opencode-ai/ui/dialog" import { InlineInput } from "@opencode-ai/ui/inline-input" +import { Spinner } from "@opencode-ai/ui/spinner" import { SessionTurn } from "@opencode-ai/ui/session-turn" import { ScrollView } from "@opencode-ai/ui/scroll-view" import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@kilocode/sdk/v2" @@ -160,7 +161,7 @@ function createTimelineStaging(input: TimelineStageInput) { } const currentTotal = input.messages().length count = Math.min(currentTotal, count + input.config.batch) - startTransition(() => setState("count", count)) + setState("count", count) if (count >= currentTotal) { setState({ completedSession: sessionKey, activeSession: "" }) frame = undefined @@ -192,8 +193,7 @@ export function MessageTimeline(props: { onAutoScrollHandleScroll: () => void onMarkScrollGesture: (target?: EventTarget | null) => void hasScrollGesture: () => boolean - isDesktop: boolean - onScrollSpyScroll: () => void + onUserScroll: () => void onTurnBackfillScroll: () => void onAutoScrollInteraction: (event: MouseEvent) => void centered: boolean @@ -204,8 +204,6 @@ export function MessageTimeline(props: { onLoadEarlier: () => void renderedUserMessages: UserMessage[] anchor: (id: string) => string - onRegisterMessage: (el: HTMLDivElement, id: string) => void - onUnregisterMessage: (id: string) => void }) { let touchGesture: number | undefined @@ -235,6 +233,40 @@ export function MessageTimeline(props: { if (!id) return idle return sync.data.session_status[id] ?? idle }) + const working = createMemo(() => !!pending() || sessionStatus().type !== "idle") + + const [slot, setSlot] = createStore({ + open: false, + show: false, + fade: false, + }) + + let f: number | undefined + const clear = () => { + if (f !== undefined) window.clearTimeout(f) + f = undefined + } + + onCleanup(clear) + createEffect( + on( + working, + (on, prev) => { + clear() + if (on) { + setSlot({ open: true, show: true, fade: false }) + return + } + if (prev) { + setSlot({ open: false, show: true, fade: true }) + f = window.setTimeout(() => setSlot({ show: false, fade: false }), 260) + return + } + setSlot({ open: false, show: false, fade: false }) + }, + { defer: true }, + ), + ) const activeMessageID = createMemo(() => { const parentID = pending()?.parentID if (parentID) { @@ -539,9 +571,9 @@ export function MessageTimeline(props: { props.onScheduleScrollState(e.currentTarget) props.onTurnBackfillScroll() if (!props.hasScrollGesture()) return + props.onUserScroll() props.onAutoScrollHandleScroll() props.onMarkScrollGesture(e.currentTarget) - if (props.isDesktop) props.onScrollSpyScroll() }} onClick={props.onAutoScrollInteraction} class="relative min-w-0 w-full h-full" @@ -573,43 +605,64 @@ export function MessageTimeline(props: { aria-label={language.t("common.goBack")} /> - - - {titleValue()} - - } +
+ + + + {titleValue()} + + } + > + { + titleRef = el + }} + value={title.draft} + disabled={title.saving} + class="text-14-medium text-text-strong grow-1 min-w-0 rounded-[6px]" + style={{ "--inline-input-shadow": "var(--shadow-xs-border-select)" }} + onInput={(event) => setTitle("draft", event.currentTarget.value)} + onKeyDown={(event) => { + event.stopPropagation() + if (event.key === "Enter") { + event.preventDefault() + void saveTitleEditor() + return + } + if (event.key === "Escape") { + event.preventDefault() + closeTitleEditor() + } + }} + onBlur={closeTitleEditor} + /> + - +
{(id) => ( @@ -707,10 +760,6 @@ export function MessageTimeline(props: {
{ - props.onRegisterMessage(el, messageID) - onCleanup(() => props.onUnregisterMessage(messageID)) - }} classList={{ "min-w-0 w-full max-w-full": true, "md:max-w-200 2xl:max-w-[1000px]": props.centered, diff --git a/packages/app/src/pages/session/scroll-spy.test.ts b/packages/app/src/pages/session/scroll-spy.test.ts deleted file mode 100644 index f3e6775cb48..00000000000 --- a/packages/app/src/pages/session/scroll-spy.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { createScrollSpy, pickOffsetId, pickVisibleId } from "./scroll-spy" - -const rect = (top: number, height = 80): DOMRect => - ({ - x: 0, - y: top, - top, - left: 0, - right: 800, - bottom: top + height, - width: 800, - height, - toJSON: () => ({}), - }) as DOMRect - -const setRect = (el: Element, top: number, height = 80) => { - Object.defineProperty(el, "getBoundingClientRect", { - configurable: true, - value: () => rect(top, height), - }) -} - -describe("pickVisibleId", () => { - test("prefers higher intersection ratio", () => { - const id = pickVisibleId( - [ - { id: "a", ratio: 0.2, top: 100 }, - { id: "b", ratio: 0.8, top: 300 }, - ], - 120, - ) - - expect(id).toBe("b") - }) - - test("breaks ratio ties by nearest line", () => { - const id = pickVisibleId( - [ - { id: "a", ratio: 0.5, top: 90 }, - { id: "b", ratio: 0.5, top: 140 }, - ], - 130, - ) - - expect(id).toBe("b") - }) -}) - -describe("pickOffsetId", () => { - test("uses binary search cutoff", () => { - const id = pickOffsetId( - [ - { id: "a", top: 0 }, - { id: "b", top: 200 }, - { id: "c", top: 400 }, - ], - 350, - ) - - expect(id).toBe("b") - }) -}) - -describe("createScrollSpy fallback", () => { - test("tracks active id from offsets and dirty refresh", () => { - const active: string[] = [] - const root = document.createElement("div") as HTMLDivElement - const one = document.createElement("div") - const two = document.createElement("div") - const three = document.createElement("div") - - root.append(one, two, three) - document.body.append(root) - - Object.defineProperty(root, "scrollTop", { configurable: true, writable: true, value: 250 }) - setRect(root, 0, 800) - setRect(one, -250) - setRect(two, -50) - setRect(three, 150) - - const queue: FrameRequestCallback[] = [] - const flush = () => { - const run = [...queue] - queue.length = 0 - for (const cb of run) cb(0) - } - - const spy = createScrollSpy({ - onActive: (id) => active.push(id), - raf: (cb) => (queue.push(cb), queue.length), - caf: () => {}, - IntersectionObserver: undefined, - ResizeObserver: undefined, - MutationObserver: undefined, - }) - - spy.setContainer(root) - spy.register(one, "a") - spy.register(two, "b") - spy.register(three, "c") - spy.onScroll() - flush() - - expect(spy.getActiveId()).toBe("b") - expect(active.at(-1)).toBe("b") - - root.scrollTop = 450 - setRect(one, -450) - setRect(two, -250) - setRect(three, -50) - spy.onScroll() - flush() - expect(spy.getActiveId()).toBe("c") - - root.scrollTop = 250 - setRect(one, -250) - setRect(two, 250) - setRect(three, 150) - spy.markDirty() - spy.onScroll() - flush() - expect(spy.getActiveId()).toBe("a") - - spy.destroy() - }) -}) diff --git a/packages/app/src/pages/session/scroll-spy.ts b/packages/app/src/pages/session/scroll-spy.ts deleted file mode 100644 index 6ef4c844c41..00000000000 --- a/packages/app/src/pages/session/scroll-spy.ts +++ /dev/null @@ -1,275 +0,0 @@ -type Visible = { - id: string - ratio: number - top: number -} - -type Offset = { - id: string - top: number -} - -type Input = { - onActive: (id: string) => void - raf?: (cb: FrameRequestCallback) => number - caf?: (id: number) => void - IntersectionObserver?: typeof globalThis.IntersectionObserver - ResizeObserver?: typeof globalThis.ResizeObserver - MutationObserver?: typeof globalThis.MutationObserver -} - -export const pickVisibleId = (list: Visible[], line: number) => { - if (list.length === 0) return - - const sorted = [...list].sort((a, b) => { - if (b.ratio !== a.ratio) return b.ratio - a.ratio - - const da = Math.abs(a.top - line) - const db = Math.abs(b.top - line) - if (da !== db) return da - db - - return a.top - b.top - }) - - return sorted[0]?.id -} - -export const pickOffsetId = (list: Offset[], cutoff: number) => { - if (list.length === 0) return - - let lo = 0 - let hi = list.length - 1 - let out = 0 - - while (lo <= hi) { - const mid = (lo + hi) >> 1 - const top = list[mid]?.top - if (top === undefined) break - - if (top <= cutoff) { - out = mid - lo = mid + 1 - continue - } - - hi = mid - 1 - } - - return list[out]?.id -} - -export const createScrollSpy = (input: Input) => { - const raf = input.raf ?? requestAnimationFrame - const caf = input.caf ?? cancelAnimationFrame - const CtorIO = input.IntersectionObserver ?? globalThis.IntersectionObserver - const CtorRO = input.ResizeObserver ?? globalThis.ResizeObserver - const CtorMO = input.MutationObserver ?? globalThis.MutationObserver - - let root: HTMLDivElement | undefined - let io: IntersectionObserver | undefined - let ro: ResizeObserver | undefined - let mo: MutationObserver | undefined - let frame: number | undefined - let active: string | undefined - let dirty = true - - const node = new Map() - const id = new WeakMap() - const visible = new Map() - let offset: Offset[] = [] - - const schedule = () => { - if (frame !== undefined) return - frame = raf(() => { - frame = undefined - update() - }) - } - - const refreshOffset = () => { - const el = root - if (!el) { - offset = [] - dirty = false - return - } - - const base = el.getBoundingClientRect().top - offset = [...node].map(([next, item]) => ({ - id: next, - top: item.getBoundingClientRect().top - base + el.scrollTop, - })) - offset.sort((a, b) => a.top - b.top) - dirty = false - } - - const update = () => { - const el = root - if (!el) return - - const line = el.getBoundingClientRect().top + 100 - const next = - pickVisibleId( - [...visible].map(([k, v]) => ({ - id: k, - ratio: v.ratio, - top: v.top, - })), - line, - ) ?? - (() => { - if (dirty) refreshOffset() - return pickOffsetId(offset, el.scrollTop + 100) - })() - - if (!next || next === active) return - active = next - input.onActive(next) - } - - const observe = () => { - const el = root - if (!el) return - - io?.disconnect() - io = undefined - if (CtorIO) { - try { - io = new CtorIO( - (entries) => { - for (const entry of entries) { - const item = entry.target - if (!(item instanceof HTMLElement)) continue - const key = id.get(item) - if (!key) continue - - if (!entry.isIntersecting || entry.intersectionRatio <= 0) { - visible.delete(key) - continue - } - - visible.set(key, { - ratio: entry.intersectionRatio, - top: entry.boundingClientRect.top, - }) - } - - schedule() - }, - { - root: el, - threshold: [0, 0.25, 0.5, 0.75, 1], - }, - ) - } catch { - io = undefined - } - } - - if (io) { - for (const item of node.values()) io.observe(item) - } - - ro?.disconnect() - ro = undefined - if (CtorRO) { - ro = new CtorRO(() => { - dirty = true - schedule() - }) - ro.observe(el) - for (const item of node.values()) ro.observe(item) - } - - mo?.disconnect() - mo = undefined - if (CtorMO) { - mo = new CtorMO(() => { - dirty = true - schedule() - }) - mo.observe(el, { subtree: true, childList: true, characterData: true }) - } - - dirty = true - schedule() - } - - const setContainer = (el?: HTMLDivElement) => { - if (root === el) return - - root = el - visible.clear() - active = undefined - observe() - } - - const register = (el: HTMLElement, key: string) => { - const prev = node.get(key) - if (prev && prev !== el) { - io?.unobserve(prev) - ro?.unobserve(prev) - } - - node.set(key, el) - id.set(el, key) - if (io) io.observe(el) - if (ro) ro.observe(el) - dirty = true - schedule() - } - - const unregister = (key: string) => { - const item = node.get(key) - if (!item) return - - io?.unobserve(item) - ro?.unobserve(item) - node.delete(key) - visible.delete(key) - dirty = true - schedule() - } - - const markDirty = () => { - dirty = true - schedule() - } - - const clear = () => { - for (const item of node.values()) { - io?.unobserve(item) - ro?.unobserve(item) - } - - node.clear() - visible.clear() - offset = [] - active = undefined - dirty = true - } - - const destroy = () => { - if (frame !== undefined) caf(frame) - frame = undefined - clear() - io?.disconnect() - ro?.disconnect() - mo?.disconnect() - io = undefined - ro = undefined - mo = undefined - root = undefined - } - - return { - setContainer, - register, - unregister, - onScroll: schedule, - markDirty, - clear, - destroy, - getActiveId: () => active, - } -} diff --git a/packages/app/src/pages/session/session-model-helpers.test.ts b/packages/app/src/pages/session/session-model-helpers.test.ts new file mode 100644 index 00000000000..23d866fb52e --- /dev/null +++ b/packages/app/src/pages/session/session-model-helpers.test.ts @@ -0,0 +1,158 @@ +import { describe, expect, test } from "bun:test" +import type { UserMessage } from "@kilocode/sdk/v2" +import { resetSessionModel, syncSessionModel } from "./session-model-helpers" + +const message = (input?: Partial>) => + ({ + id: "msg", + sessionID: "session", + role: "user", + time: { created: 1 }, + agent: input?.agent ?? "build", + model: input?.model ?? { providerID: "anthropic", modelID: "claude-sonnet-4" }, + variant: input?.variant, + }) as UserMessage + +describe("syncSessionModel", () => { + test("restores the last message model and variant", () => { + const calls: unknown[] = [] + + syncSessionModel( + { + agent: { + current() { + return undefined + }, + set(value) { + calls.push(["agent", value]) + }, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return { id: "claude-sonnet-4", provider: { id: "anthropic" } } + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }, + message({ variant: "high" }), + ) + + expect(calls).toEqual([ + ["agent", "build"], + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ["variant", "high"], + ]) + }) + + test("skips variant when the model falls back", () => { + const calls: unknown[] = [] + + syncSessionModel( + { + agent: { + current() { + return undefined + }, + set(value) { + calls.push(["agent", value]) + }, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return { id: "gpt-5", provider: { id: "openai" } } + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }, + message({ variant: "high" }), + ) + + expect(calls).toEqual([ + ["agent", "build"], + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ]) + }) +}) + +describe("resetSessionModel", () => { + test("restores the current agent defaults", () => { + const calls: unknown[] = [] + + resetSessionModel({ + agent: { + current() { + return { + model: { providerID: "anthropic", modelID: "claude-sonnet-4" }, + variant: "high", + } + }, + set() {}, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return undefined + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }) + + expect(calls).toEqual([ + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ["variant", "high"], + ]) + }) + + test("clears the variant when the agent has none", () => { + const calls: unknown[] = [] + + resetSessionModel({ + agent: { + current() { + return { + model: { providerID: "anthropic", modelID: "claude-sonnet-4" }, + } + }, + set() {}, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return undefined + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }) + + expect(calls).toEqual([ + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ["variant", undefined], + ]) + }) +}) diff --git a/packages/app/src/pages/session/session-model-helpers.ts b/packages/app/src/pages/session/session-model-helpers.ts new file mode 100644 index 00000000000..c02a455f03b --- /dev/null +++ b/packages/app/src/pages/session/session-model-helpers.ts @@ -0,0 +1,48 @@ +import type { UserMessage } from "@kilocode/sdk/v2" +import { batch } from "solid-js" + +type Local = { + agent: { + current(): + | { + model?: UserMessage["model"] + variant?: string + } + | undefined + set(name: string | undefined): void + } + model: { + set(model: UserMessage["model"] | undefined): void + current(): + | { + id: string + provider: { id: string } + } + | undefined + variant: { + set(value: string | undefined): void + } + } +} + +export const resetSessionModel = (local: Local) => { + const agent = local.agent.current() + if (!agent) return + batch(() => { + local.model.set(agent.model) + local.model.variant.set(agent.variant) + }) +} + +export const syncSessionModel = (local: Local, msg: UserMessage) => { + batch(() => { + local.agent.set(msg.agent) + local.model.set(msg.model) + }) + + const model = local.model.current() + if (!model) return + if (model.provider.id !== msg.model.providerID) return + if (model.id !== msg.model.modelID) return + local.model.variant.set(msg.variant) +} diff --git a/packages/app/src/pages/session/session-side-panel.tsx b/packages/app/src/pages/session/session-side-panel.tsx index ad802d15d18..590f5b6d9ba 100644 --- a/packages/app/src/pages/session/session-side-panel.tsx +++ b/packages/app/src/pages/session/session-side-panel.tsx @@ -23,7 +23,7 @@ import { useLayout } from "@/context/layout" import { useSync } from "@/context/sync" import { createFileTabListSync } from "@/pages/session/file-tab-scroll" import { FileTabContent } from "@/pages/session/file-tabs" -import { createOpenSessionFileTab, getTabReorderIndex } from "@/pages/session/helpers" +import { createOpenSessionFileTab, getTabReorderIndex, type Sizing } from "@/pages/session/helpers" import { StickyAddButton } from "@/pages/session/review-tab" import { setSessionHandoff } from "@/pages/session/handoff" @@ -31,6 +31,8 @@ export function SessionSidePanel(props: { reviewPanel: () => JSX.Element activeDiff?: string focusReviewDiff: (path: string) => void + reviewSnap: boolean + size: Sizing }) { const params = useParams() const layout = useLayout() @@ -46,8 +48,15 @@ export function SessionSidePanel(props: { const view = createMemo(() => layout.view(sessionKey)) const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened()) - const open = createMemo(() => isDesktop() && (view().reviewPanel.opened() || layout.fileTree.opened())) + const fileOpen = createMemo(() => isDesktop() && layout.fileTree.opened()) + const open = createMemo(() => reviewOpen() || fileOpen()) const reviewTab = createMemo(() => isDesktop()) + const panelWidth = createMemo(() => { + if (!open()) return "0px" + if (reviewOpen()) return `calc(100% - ${layout.session.width()}px)` + return `${layout.fileTree.width()}px` + }) + const treeWidth = createMemo(() => (fileOpen() ? `${layout.fileTree.width()}px` : "0px")) const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : [])) @@ -60,6 +69,12 @@ export function SessionSidePanel(props: { return sync.data.session_diff[id] !== undefined }) + const reviewEmptyKey = createMemo(() => { + if (sync.project && !sync.project.vcs) return "session.review.noVcs" + if (sync.data.config.snapshot === false) return "session.review.noSnapshot" + return "session.review.noChanges" + }) + const diffFiles = createMemo(() => diffs().map((d) => d.file)) const kinds = createMemo(() => { const merge = (a: "add" | "del" | "mix" | undefined, b: "add" | "del" | "mix") => { @@ -87,6 +102,21 @@ export function SessionSidePanel(props: { return out }) + const empty = (msg: string) => ( +
+
+
+
{msg}
+
+
+ ) + + const nofiles = createMemo(() => { + const state = file.tree.state("") + if (!state?.loaded) return false + return file.tree.children("").length === 0 + }) + const normalizeTab = (tab: string) => { if (!tab.startsWith("file://")) return tab return file.tab(tab) @@ -145,17 +175,8 @@ export function SessionSidePanel(props: { const [store, setStore] = createStore({ activeDraggable: undefined as string | undefined, - fileTreeScrolled: false, }) - let changesEl: HTMLDivElement | undefined - let allEl: HTMLDivElement | undefined - - const syncFileTreeScrolled = (el?: HTMLDivElement) => { - const next = (el?.scrollTop ?? 0) > 0 - setStore("fileTreeScrolled", (current) => (current === next ? current : next)) - } - const handleDragStart = (event: unknown) => { const id = getDraggableId(event) if (!id) return @@ -176,11 +197,6 @@ export function SessionSidePanel(props: { setStore("activeDraggable", undefined) } - createEffect(() => { - if (!layout.fileTree.opened()) return - syncFileTreeScrolled(fileTreeTab() === "changes" ? changesEl : allEl) - }) - createEffect(() => { if (!file.ready()) return @@ -203,149 +219,172 @@ export function SessionSidePanel(props: { }) return ( - + ) diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index cc4c17ee216..8fd652e9032 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -17,7 +17,7 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useTerminal, type LocalPTY } from "@/context/terminal" import { terminalTabLabel } from "@/pages/session/terminal-label" -import { focusTerminalById } from "@/pages/session/helpers" +import { createPresence, createSizing, focusTerminalById } from "@/pages/session/helpers" import { getTerminalHandoff, setTerminalHandoff } from "@/pages/session/handoff" export function TerminalPanel() { @@ -33,8 +33,11 @@ export function TerminalPanel() { const opened = createMemo(() => view().terminal.opened()) const open = createMemo(() => isDesktop() && opened()) + const panel = createPresence(open) + const size = createSizing() const height = createMemo(() => layout.terminal.height()) const close = () => view().terminal.close() + let root: HTMLDivElement | undefined const [store, setStore] = createStore({ autoCreated: false, @@ -67,7 +70,7 @@ export function TerminalPanel() { on( () => terminal.active(), (activeId) => { - if (!activeId || !open()) return + if (!activeId || !panel.open()) return if (document.activeElement instanceof HTMLElement) { document.activeElement.blur() } @@ -76,6 +79,14 @@ export function TerminalPanel() { ), ) + createEffect(() => { + if (panel.open()) return + const active = document.activeElement + if (!(active instanceof HTMLElement)) return + if (!root?.contains(active)) return + active.blur() + }) + createEffect(() => { const dir = params.dir if (!dir) return @@ -133,120 +144,143 @@ export function TerminalPanel() { } return ( - +
- - -
- - {(title) => ( -
- {title} -
- )} -
-
-
- {language.t("common.loading")} - {language.t("common.loading.ellipsis")} +
+
size.start()}> + { + size.touch() + layout.terminal.resize(next) + }} + onCollapse={close} + /> +
+ +
+ + {(title) => ( +
+ {title} +
+ )} +
+
+
+ {language.t("common.loading")} + {language.t("common.loading.ellipsis")} +
+
+
+ {language.t("terminal.loading")}
-
{language.t("terminal.loading")}
-
- } - > - - - -
- terminal.open(id)} - class="!h-auto !flex-none" - > - - - - {(id) => ( - - {(pty) => } - - )} - - -
- - - -
-
-
-
- - {(id) => ( - - {(pty) => ( -
- terminal.clone(id)} /> + + + +
+ terminal.open(id)} + class="!h-auto !flex-none" + > + + + + {(id) => ( + + {(pty) => } + + )} + + +
+ + + +
+
+
+
+ + {(id) => ( + + {(pty) => ( +
+ terminal.trim(id)} + onCleanup={terminal.update} + onConnectError={() => terminal.clone(id)} + /> +
+ )} +
+ )} +
+
+
+ + + {(draggedId) => ( + + {(t) => ( +
+ {terminalTabLabel({ + title: t().title, + titleNumber: t().titleNumber, + t: language.t as (key: string, vars?: Record) => string, + })}
)}
)}
-
-
- - - {(draggedId) => ( - - {(t) => ( -
- {terminalTabLabel({ - title: t().title, - titleNumber: t().titleNumber, - t: language.t as (key: string, vars?: Record) => string, - })} -
- )} -
- )} -
-
- - + + + +
) diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx index 00385548357..47f12bba54a 100644 --- a/packages/app/src/pages/session/use-session-commands.tsx +++ b/packages/app/src/pages/session/use-session-commands.tsx @@ -261,24 +261,35 @@ export const useSessionCommands = (actions: SessionCommandContext) => { }), ]) + const isAutoAcceptActive = () => { + const sessionID = params.id + if (sessionID) return permission.isAutoAccepting(sessionID, sdk.directory) + return permission.isAutoAcceptingDirectory(sdk.directory) + } + const permissionCommands = createMemo(() => [ permissionsCommand({ id: "permissions.autoaccept", - title: - params.id && permission.isAutoAccepting(params.id, sdk.directory) - ? language.t("command.permissions.autoaccept.disable") - : language.t("command.permissions.autoaccept.enable"), + title: isAutoAcceptActive() + ? language.t("command.permissions.autoaccept.disable") + : language.t("command.permissions.autoaccept.enable"), keybind: "mod+shift+a", - disabled: !params.id || !permission.permissionsEnabled(), + disabled: false, onSelect: () => { const sessionID = params.id - if (!sessionID) return - permission.toggleAutoAccept(sessionID, sdk.directory) + if (sessionID) { + permission.toggleAutoAccept(sessionID, sdk.directory) + } else { + permission.toggleAutoAcceptDirectory(sdk.directory) + } + const active = sessionID + ? permission.isAutoAccepting(sessionID, sdk.directory) + : permission.isAutoAcceptingDirectory(sdk.directory) showToast({ - title: permission.isAutoAccepting(sessionID, sdk.directory) + title: active ? language.t("toast.permissions.autoaccept.on.title") : language.t("toast.permissions.autoaccept.off.title"), - description: permission.isAutoAccepting(sessionID, sdk.directory) + description: active ? language.t("toast.permissions.autoaccept.on.description") : language.t("toast.permissions.autoaccept.off.description"), }) diff --git a/packages/app/src/pages/session/use-session-hash-scroll.test.ts b/packages/app/src/pages/session/use-session-hash-scroll.test.ts index 844f5451e39..7f3389baaac 100644 --- a/packages/app/src/pages/session/use-session-hash-scroll.test.ts +++ b/packages/app/src/pages/session/use-session-hash-scroll.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { messageIdFromHash } from "./use-session-hash-scroll" +import { messageIdFromHash } from "./message-id-from-hash" describe("messageIdFromHash", () => { test("parses hash with leading #", () => { diff --git a/packages/app/src/pages/session/use-session-hash-scroll.ts b/packages/app/src/pages/session/use-session-hash-scroll.ts index 680c93e4b4f..8e849e3db7f 100644 --- a/packages/app/src/pages/session/use-session-hash-scroll.ts +++ b/packages/app/src/pages/session/use-session-hash-scroll.ts @@ -1,12 +1,9 @@ +import type { UserMessage } from "@kilocode/sdk/v2" +import { useLocation, useNavigate } from "@solidjs/router" import { createEffect, createMemo, onCleanup, onMount } from "solid-js" -import { UserMessage } from "@kilocode/sdk/v2" +import { messageIdFromHash } from "./message-id-from-hash" -export const messageIdFromHash = (hash: string) => { - const value = hash.startsWith("#") ? hash.slice(1) : hash - const match = value.match(/^message-(.+)$/) - if (!match) return - return match[1] -} +export { messageIdFromHash } from "./message-id-from-hash" export const useSessionHashScroll = (input: { sessionKey: () => string @@ -29,14 +26,40 @@ export const useSessionHashScroll = (input: { const messageById = createMemo(() => new Map(visibleUserMessages().map((m) => [m.id, m]))) const messageIndex = createMemo(() => new Map(visibleUserMessages().map((m, i) => [m.id, i]))) let pendingKey = "" + let clearing = false + + const location = useLocation() + const navigate = useNavigate() + + const frames = new Set() + const queue = (fn: () => void) => { + const id = requestAnimationFrame(() => { + frames.delete(id) + fn() + }) + frames.add(id) + } + const cancel = () => { + for (const id of frames) cancelAnimationFrame(id) + frames.clear() + } const clearMessageHash = () => { - if (!window.location.hash) return - window.history.replaceState(null, "", window.location.href.replace(/#.*$/, "")) + cancel() + input.consumePendingMessage(input.sessionKey()) + if (input.pendingMessage()) input.setPendingMessage(undefined) + if (!location.hash) return + clearing = true + navigate(location.pathname + location.search, { replace: true }) } const updateHash = (id: string) => { - window.history.replaceState(null, "", `#${input.anchor(id)}`) + const hash = `#${input.anchor(id)}` + if (location.hash === hash) return + clearing = false + navigate(location.pathname + location.search + hash, { + replace: true, + }) } const scrollToElement = (el: HTMLElement, behavior: ScrollBehavior) => { @@ -52,55 +75,42 @@ export const useSessionHashScroll = (input: { return true } + const seek = (id: string, behavior: ScrollBehavior, left = 4): boolean => { + const el = document.getElementById(input.anchor(id)) + if (el) return scrollToElement(el, behavior) + if (left <= 0) return false + queue(() => { + seek(id, behavior, left - 1) + }) + return false + } + const scrollToMessage = (message: UserMessage, behavior: ScrollBehavior = "smooth") => { + cancel() if (input.currentMessageId() !== message.id) input.setActiveMessage(message) const index = messageIndex().get(message.id) ?? -1 if (index !== -1 && index < input.turnStart()) { input.setTurnStart(index) - requestAnimationFrame(() => { - const el = document.getElementById(input.anchor(message.id)) - if (!el) { - requestAnimationFrame(() => { - const next = document.getElementById(input.anchor(message.id)) - if (!next) return - scrollToElement(next, behavior) - }) - return - } - scrollToElement(el, behavior) + queue(() => { + seek(message.id, behavior) }) updateHash(message.id) return } - const el = document.getElementById(input.anchor(message.id)) - if (!el) { - updateHash(message.id) - requestAnimationFrame(() => { - const next = document.getElementById(input.anchor(message.id)) - if (!next) return - if (!scrollToElement(next, behavior)) return - }) - return - } - if (scrollToElement(el, behavior)) { + if (seek(message.id, behavior)) { updateHash(message.id) return } - requestAnimationFrame(() => { - const next = document.getElementById(input.anchor(message.id)) - if (!next) return - if (!scrollToElement(next, behavior)) return - }) updateHash(message.id) } const applyHash = (behavior: ScrollBehavior) => { - const hash = window.location.hash.slice(1) + const hash = location.hash.slice(1) if (!hash) { input.autoScroll.forceScrollToBottom() const el = input.scroller() @@ -132,8 +142,11 @@ export const useSessionHashScroll = (input: { } createEffect(() => { + const hash = location.hash + if (!hash) clearing = false if (!input.sessionID() || !input.messagesReady()) return - requestAnimationFrame(() => applyHash("auto")) + cancel() + queue(() => applyHash("auto")) }) createEffect(() => { @@ -155,32 +168,29 @@ export const useSessionHashScroll = (input: { } } - if (!targetId) targetId = messageIdFromHash(window.location.hash) + if (!targetId && !clearing) targetId = messageIdFromHash(location.hash) if (!targetId) return - if (input.currentMessageId() === targetId) return + const pending = input.pendingMessage() === targetId const msg = messageById().get(targetId) if (!msg) return - if (input.pendingMessage() === targetId) input.setPendingMessage(undefined) + if (pending) input.setPendingMessage(undefined) + if (input.currentMessageId() === targetId && !pending) return + input.autoScroll.pause() - requestAnimationFrame(() => scrollToMessage(msg, "auto")) + cancel() + queue(() => scrollToMessage(msg, "auto")) }) onMount(() => { if (typeof window !== "undefined" && "scrollRestoration" in window.history) { window.history.scrollRestoration = "manual" } - - const handler = () => { - if (!input.sessionID() || !input.messagesReady()) return - requestAnimationFrame(() => applyHash("auto")) - } - - window.addEventListener("hashchange", handler) - onCleanup(() => window.removeEventListener("hashchange", handler)) }) + onCleanup(cancel) + return { clearMessageHash, scrollToMessage, diff --git a/packages/app/src/theme-preload.test.ts b/packages/app/src/theme-preload.test.ts new file mode 100644 index 00000000000..00d7da23948 --- /dev/null +++ b/packages/app/src/theme-preload.test.ts @@ -0,0 +1,46 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +const src = await Bun.file(new URL("../public/oc-theme-preload.js", import.meta.url)).text() + +const run = () => Function(src)() + +beforeEach(() => { + document.head.innerHTML = "" + document.documentElement.removeAttribute("data-theme") + document.documentElement.removeAttribute("data-color-scheme") + localStorage.clear() + Object.defineProperty(window, "matchMedia", { + value: () => + ({ + matches: false, + }) as MediaQueryList, + configurable: true, + }) +}) + +describe("theme preload", () => { + test("migrates legacy oc-1 to oc-2 before mount", () => { + localStorage.setItem("opencode-theme-id", "oc-1") + localStorage.setItem("opencode-theme-css-light", "--background-base:#fff;") + localStorage.setItem("opencode-theme-css-dark", "--background-base:#000;") + + run() + + expect(document.documentElement.dataset.theme).toBe("oc-2") + expect(document.documentElement.dataset.colorScheme).toBe("light") + expect(localStorage.getItem("opencode-theme-id")).toBe("oc-2") + expect(localStorage.getItem("opencode-theme-css-light")).toBeNull() + expect(localStorage.getItem("opencode-theme-css-dark")).toBeNull() + expect(document.getElementById("oc-theme-preload")).toBeNull() + }) + + test("keeps cached css for non-default themes", () => { + localStorage.setItem("opencode-theme-id", "nightowl") + localStorage.setItem("opencode-theme-css-light", "--background-base:#fff;") + + run() + + expect(document.documentElement.dataset.theme).toBe("nightowl") + expect(document.getElementById("oc-theme-preload")?.textContent).toContain("--background-base:#fff;") + }) +}) diff --git a/packages/app/src/utils/notification-click.ts b/packages/app/src/utils/notification-click.ts index 94086c59593..316b2782062 100644 --- a/packages/app/src/utils/notification-click.ts +++ b/packages/app/src/utils/notification-click.ts @@ -7,6 +7,7 @@ export const setNavigate = (fn: (href: string) => void) => { export const handleNotificationClick = (href?: string) => { window.focus() if (!href) return - if (nav) nav(href) - else window.location.assign(href) + if (nav) return nav(href) + console.warn("notification-click: navigate function not set, falling back to window.location.assign") + window.location.assign(href) } diff --git a/packages/app/src/utils/persist.test.ts b/packages/app/src/utils/persist.test.ts index 2a2c349b755..673acd224d2 100644 --- a/packages/app/src/utils/persist.test.ts +++ b/packages/app/src/utils/persist.test.ts @@ -104,4 +104,12 @@ describe("persist localStorage resilience", () => { const result = persistTesting.normalize({ value: "ok" }, '{"value":"\\x"}') expect(result).toBeUndefined() }) + + test("workspace storage sanitizes Windows filename characters", () => { + const result = persistTesting.workspaceStorage("C:\\Users\\foo") + + expect(result).toStartWith("opencode.workspace.") + expect(result.endsWith(".dat")).toBeTrue() + expect(/[:\\/]/.test(result)).toBeFalse() + }) }) diff --git a/packages/app/src/utils/persist.ts b/packages/app/src/utils/persist.ts index 91c504742a9..bee2f3e7d1f 100644 --- a/packages/app/src/utils/persist.ts +++ b/packages/app/src/utils/persist.ts @@ -204,7 +204,7 @@ function normalize(defaults: unknown, raw: string, migrate?: (value: unknown) => } function workspaceStorage(dir: string) { - const head = dir.slice(0, 12) || "workspace" + const head = (dir.slice(0, 12) || "workspace").replace(/[^a-zA-Z0-9._-]/g, "-") const sum = checksum(dir) ?? "0" return `opencode.workspace.${head}.${sum}.dat` } @@ -300,6 +300,7 @@ export const PersistTesting = { localStorageDirect, localStorageWithPrefix, normalize, + workspaceStorage, } export const Persist = { diff --git a/packages/app/src/utils/server-errors.test.ts b/packages/app/src/utils/server-errors.test.ts index 1969d1afc27..1f53bb8cf66 100644 --- a/packages/app/src/utils/server-errors.test.ts +++ b/packages/app/src/utils/server-errors.test.ts @@ -1,8 +1,37 @@ import { describe, expect, test } from "bun:test" -import type { ConfigInvalidError } from "./server-errors" -import { formatServerError, parseReabaleConfigInvalidError } from "./server-errors" +import type { ConfigInvalidError, ProviderModelNotFoundError } from "./server-errors" +import { formatServerError, parseReadableConfigInvalidError } from "./server-errors" -describe("parseReabaleConfigInvalidError", () => { +function fill(text: string, vars?: Record) { + if (!vars) return text + return text.replace(/{{\s*(\w+)\s*}}/g, (_, key: string) => { + const value = vars[key] + if (value === undefined) return "" + return String(value) + }) +} + +function useLanguageMock() { + const dict: Record = { + "error.chain.unknown": "Erro desconhecido", + "error.chain.configInvalid": "Arquivo de config em {{path}} invalido", + "error.chain.configInvalidWithMessage": "Arquivo de config em {{path}} invalido: {{message}}", + "error.chain.modelNotFound": "Modelo nao encontrado: {{provider}}/{{model}}", + "error.chain.didYouMean": "Voce quis dizer: {{suggestions}}", + "error.chain.checkConfig": "Revise provider/model no config", + } + return { + t(key: string, vars?: Record) { + const text = dict[key] + if (!text) return key + return fill(text, vars) + }, + } +} + +const language = useLanguageMock() + +describe("parseReadableConfigInvalidError", () => { test("formats issues with file path", () => { const error = { name: "ConfigInvalidError", @@ -15,10 +44,10 @@ describe("parseReabaleConfigInvalidError", () => { }, } satisfies ConfigInvalidError - const result = parseReabaleConfigInvalidError(error) + const result = parseReadableConfigInvalidError(error, language.t) expect(result).toBe( - ["Invalid configuration", "opencode.config.ts", "settings.host: Required", "mode: Invalid"].join("\n"), + ["Arquivo de config em opencode.config.ts invalido: settings.host: Required", "mode: Invalid"].join("\n"), ) }) @@ -31,9 +60,9 @@ describe("parseReabaleConfigInvalidError", () => { }, } satisfies ConfigInvalidError - const result = parseReabaleConfigInvalidError(error) + const result = parseReadableConfigInvalidError(error, language.t) - expect(result).toBe(["Invalid configuration", "Bad value"].join("\n")) + expect(result).toBe("Arquivo de config em config invalido: Bad value") }) }) @@ -46,24 +75,57 @@ describe("formatServerError", () => { }, } satisfies ConfigInvalidError - const result = formatServerError(error) + const result = formatServerError(error, language.t) - expect(result).toBe(["Invalid configuration", "Missing host"].join("\n")) + expect(result).toBe("Arquivo de config em config invalido: Missing host") }) test("returns error messages", () => { - expect(formatServerError(new Error("Request failed with status 503"))).toBe("Request failed with status 503") + expect(formatServerError(new Error("Request failed with status 503"), language.t)).toBe( + "Request failed with status 503", + ) }) test("returns provided string errors", () => { - expect(formatServerError("Failed to connect to server")).toBe("Failed to connect to server") + expect(formatServerError("Failed to connect to server", language.t)).toBe("Failed to connect to server") }) - test("falls back to unknown", () => { - expect(formatServerError(0)).toBe("Unknown error") + test("uses translated unknown fallback", () => { + expect(formatServerError(0, language.t)).toBe("Erro desconhecido") }) test("falls back for unknown error objects and names", () => { - expect(formatServerError({ name: "ServerTimeoutError", data: { seconds: 30 } })).toBe("Unknown error") + expect(formatServerError({ name: "ServerTimeoutError", data: { seconds: 30 } }, language.t)).toBe( + "Erro desconhecido", + ) + }) + + test("formats provider model errors using provider/model", () => { + const error = { + name: "ProviderModelNotFoundError", + data: { + providerID: "openai", + modelID: "gpt-4.1", + }, + } satisfies ProviderModelNotFoundError + + expect(formatServerError(error, language.t)).toBe( + ["Modelo nao encontrado: openai/gpt-4.1", "Revise provider/model no config"].join("\n"), + ) + }) + + test("formats provider model suggestions", () => { + const error = { + name: "ProviderModelNotFoundError", + data: { + providerID: "x", + modelID: "y", + suggestions: ["x/y2", "x/y3"], + }, + } satisfies ProviderModelNotFoundError + + expect(formatServerError(error, language.t)).toBe( + ["Modelo nao encontrado: x/y", "Voce quis dizer: x/y2, x/y3", "Revise provider/model no config"].join("\n"), + ) }) }) diff --git a/packages/app/src/utils/server-errors.ts b/packages/app/src/utils/server-errors.ts index 85ebca13206..2c3a8c54dbb 100644 --- a/packages/app/src/utils/server-errors.ts +++ b/packages/app/src/utils/server-errors.ts @@ -7,28 +7,31 @@ export type ConfigInvalidError = { } } -type Label = { - unknown: string - invalidConfiguration: string -} - -const fallback: Label = { - unknown: "Unknown error", - invalidConfiguration: "Invalid configuration", -} - -function resolveLabel(labels: Partial
+ } + /> + ) +} + +export function ContextToolExpandedList(props: { parts: ToolPart[]; expanded: boolean }) { + let contentRef: HTMLDivElement | undefined + let bodyRef: HTMLDivElement | undefined + let scrollRef: HTMLDivElement | undefined + const updateMask = () => { + if (scrollRef) updateScrollMask(scrollRef) + } + + useCollapsible({ + content: () => contentRef, + body: () => bodyRef, + open: () => props.expanded, + onOpen: updateMask, + }) + + return ( +
+
+
+ + {(part) => { + const label = createMemo(() => contextToolLabel(part)) + return ( +
+ {label().action} + {label().detail} +
+ ) + }} +
+
+
+
+ ) +} + +export function ContextToolRollingResults(props: { parts: ToolPart[]; pending: boolean }) { + const reduce = useReducedMotion() + const wiped = new Set() + const [mounted, setMounted] = createSignal(false) + onMount(() => setMounted(true)) + const show = () => mounted() && props.pending + const opacity = useSpring(() => (show() ? 1 : 0), GROW_SPRING) + const blur = useSpring(() => (show() ? 0 : 2), GROW_SPRING) + return ( +
+ part.callID || part.id} + render={(part) => { + const label = createMemo(() => contextToolLabel(part)) + const k = part.callID || part.id + return ( +
+ {label().action} + {(() => { + const [detailRef, setDetailRef] = createSignal() + useRowWipe({ + id: () => k, + text: () => label().detail, + ref: detailRef, + seen: wiped, + }) + return ( + + {label().detail} + + ) + })()} +
+ ) + }} + /> +
+ ) +} diff --git a/packages/kilo-ui/src/components/diff.tsx b/packages/kilo-ui/src/components/diff.tsx index bd6cb7bcfdc..a96af21fe11 100644 --- a/packages/kilo-ui/src/components/diff.tsx +++ b/packages/kilo-ui/src/components/diff.tsx @@ -1,7 +1,7 @@ import { sampledChecksum } from "@opencode-ai/util/encode" import { FileDiff, type FileDiffOptions, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs" import { createMediaQuery } from "@solid-primitives/media" -import { createEffect, createMemo, createSignal, onCleanup, splitProps } from "solid-js" +import { createEffect, createMemo, createSignal, on, onCleanup, splitProps, untrack } from "solid-js" import { createDefaultOptions, type DiffProps, styleVariables } from "@opencode-ai/ui/pierre" import { acquireVirtualizer, virtualMetrics } from "@opencode-ai/ui/pierre/virtualizer" import { getWorkerPool } from "@opencode-ai/ui/pierre/worker" @@ -545,7 +545,6 @@ export function Diff(props: DiffProps) { const opts = options() const workerPool = large() ? getWorkerPool("unified") : getWorkerPool(props.diffStyle) const virtualizer = getVirtualizer() - const annotations = local.annotations const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : "" const afterContents = typeof local.after?.contents === "string" ? local.after.contents : "" @@ -572,7 +571,7 @@ export function Diff(props: DiffProps) { contents: afterContents, cacheKey: cacheKey(afterContents), }, - lineAnnotations: annotations, + lineAnnotations: untrack(() => local.annotations), containerWrapper: container, }) @@ -582,6 +581,23 @@ export function Diff(props: DiffProps) { notifyRendered() }) + // Separate effect for annotation-only updates. When annotations change but + // file contents / options stay the same, this avoids the full teardown+rebuild + // in the render effect above. Pierre's setLineAnnotations + rerender handles + // incremental DOM patching of annotation slots. + // defer: true skips the initial run (the main effect already passed annotations). + createEffect( + on( + () => local.annotations, + (annotations) => { + if (!instance) return + instance.setLineAnnotations(annotations ?? []) + instance.rerender() + }, + { defer: true }, + ), + ) + createEffect(() => { if (typeof document === "undefined") return if (typeof MutationObserver === "undefined") return diff --git a/packages/kilo-ui/src/components/grow-box.tsx b/packages/kilo-ui/src/components/grow-box.tsx new file mode 100644 index 00000000000..c8ea6f3b3a9 --- /dev/null +++ b/packages/kilo-ui/src/components/grow-box.tsx @@ -0,0 +1,432 @@ +import { createEffect, on, type JSX, onMount, onCleanup } from "solid-js" +import { useReducedMotion } from "../hooks/use-reduced-motion" +import { animate, tunableSpringValue, type AnimationPlaybackControls, GROW_SPRING, type SpringConfig } from "./motion" + +export interface GrowBoxProps { + children: JSX.Element + /** Enable animation. When false, content shows immediately at full height. */ + animate?: boolean + /** Animate height from 0 to content height. Default: true. */ + grow?: boolean + /** Keep watching body size and animate subsequent height changes. Default: false. */ + watch?: boolean + /** Fade in body content (opacity + blur). Default: true. */ + fade?: boolean + /** Top padding in px on the body wrapper. Default: 0. */ + gap?: number + /** Reset to height:auto after grow completes, or stay at fixed px. Default: true. */ + autoHeight?: boolean + /** Controlled visibility for animating open/close without unmounting children. */ + open?: boolean + /** Animate controlled open/close changes after mount. Default: true. */ + animateToggle?: boolean + /** data-slot attribute on the root div. */ + slot?: string + /** CSS class on the root div. */ + class?: string + /** Override mount and resize spring config. Default: GROW_SPRING. */ + spring?: SpringConfig + /** Override controlled open/close spring config. Default: spring. */ + toggleSpring?: SpringConfig + /** Show a temporary bottom edge fade while height animation is running. */ + edge?: boolean + /** Edge fade height in px. Default: 20. */ + edgeHeight?: number + /** Edge fade opacity (0-1). Default: 1. */ + edgeOpacity?: number + /** Delay before edge fades out after height settles. Default: 320. */ + edgeIdle?: number + /** Edge fade-out duration in seconds. Default: 0.24. */ + edgeFade?: number + /** Edge fade-in duration in seconds. Default: 0.2. */ + edgeRise?: number +} + +/** + * Wraps children in a container that animates from zero height on mount. + * + * Includes a ResizeObserver so content changes after mount are also spring-animated. + * Used for timeline turns, assistant part groups, and user messages. + */ +export function GrowBox(props: GrowBoxProps) { + const reduce = useReducedMotion() + const spring = () => props.spring ?? GROW_SPRING + const toggleSpring = () => props.toggleSpring ?? spring() + let mode: "mount" | "toggle" = "mount" + let root: HTMLDivElement | undefined + let body: HTMLDivElement | undefined + let fadeAnim: AnimationPlaybackControls | undefined + let edgeRef: HTMLDivElement | undefined + let edgeAnim: AnimationPlaybackControls | undefined + let edgeTimer: ReturnType | undefined + let edgeOn = false + let mountFrame: number | undefined + let resizeFrame: number | undefined + let observer: ResizeObserver | undefined + let springTarget = -1 + const height = tunableSpringValue(0, { + type: "spring", + get visualDuration() { + return (mode === "toggle" ? toggleSpring() : spring()).visualDuration + }, + get bounce() { + return (mode === "toggle" ? toggleSpring() : spring()).bounce + }, + }) + + const gap = () => Math.max(0, props.gap ?? 0) + const grow = () => props.grow !== false + const watch = () => props.watch === true + const open = () => props.open !== false + const animateToggle = () => props.animateToggle !== false + const edge = () => props.edge === true + const edgeHeight = () => Math.max(0, props.edgeHeight ?? 20) + const edgeOpacity = () => Math.min(1, Math.max(0, props.edgeOpacity ?? 1)) + const edgeIdle = () => Math.max(0, props.edgeIdle ?? 320) + const edgeFade = () => Math.max(0.05, props.edgeFade ?? 0.24) + const edgeRise = () => Math.max(0.05, props.edgeRise ?? 0.2) + const animated = () => props.animate !== false && !reduce() + const edgeReady = () => animated() && open() && edge() && edgeHeight() > 0 + + const stopEdgeTimer = () => { + if (edgeTimer === undefined) return + clearTimeout(edgeTimer) + edgeTimer = undefined + } + + const hideEdge = (instant = false) => { + stopEdgeTimer() + if (!edgeRef) { + edgeOn = false + return + } + edgeAnim?.stop() + edgeAnim = undefined + if (instant || reduce()) { + edgeRef.style.opacity = "0" + edgeOn = false + return + } + if (!edgeOn) { + edgeRef.style.opacity = "0" + return + } + const current = animate(edgeRef, { opacity: 0 }, { type: "spring", visualDuration: edgeFade(), bounce: 0 }) + edgeAnim = current + current.finished + .catch(() => {}) + .finally(() => { + if (edgeAnim !== current) return + edgeAnim = undefined + if (!edgeRef) return + edgeRef.style.opacity = "0" + edgeOn = false + }) + } + + const showEdge = () => { + stopEdgeTimer() + if (!edgeRef) return + if (reduce()) { + edgeRef.style.opacity = `${edgeOpacity()}` + edgeOn = true + return + } + if (edgeOn && edgeAnim === undefined) { + edgeRef.style.opacity = `${edgeOpacity()}` + return + } + edgeAnim?.stop() + edgeAnim = undefined + if (!edgeOn) edgeRef.style.opacity = "0" + const current = animate( + edgeRef, + { opacity: edgeOpacity() }, + { type: "spring", visualDuration: edgeRise(), bounce: 0 }, + ) + edgeAnim = current + edgeOn = true + current.finished + .catch(() => {}) + .finally(() => { + if (edgeAnim !== current) return + edgeAnim = undefined + if (!edgeRef) return + edgeRef.style.opacity = `${edgeOpacity()}` + }) + } + + const queueEdgeHide = () => { + stopEdgeTimer() + if (!edgeOn) return + if (edgeIdle() <= 0) { + hideEdge() + return + } + edgeTimer = setTimeout(() => { + edgeTimer = undefined + hideEdge() + }, edgeIdle()) + } + + const hideBody = () => { + if (!body) return + body.style.opacity = "0" + body.style.filter = "blur(2px)" + } + + const clearBody = () => { + if (!body) return + body.style.opacity = "" + body.style.filter = "" + } + + const fadeBodyIn = (nextMode: "mount" | "toggle" = "mount") => { + if (props.fade === false || !body) return + if (reduce()) { + clearBody() + return + } + hideBody() + fadeAnim?.stop() + fadeAnim = animate(body, { opacity: 1, filter: "blur(0px)" }, nextMode === "toggle" ? toggleSpring() : spring()) + fadeAnim.finished.then(() => { + if (!body || !open()) return + clearBody() + }) + } + + const setInstant = (visible: boolean) => { + const next = visible ? targetHeight() : 0 + springTarget = next + height.jump(next) + root!.style.height = visible ? "" : "0px" + root!.style.overflow = visible ? "" : "clip" + hideEdge(true) + if (visible || props.fade === false) clearBody() + else hideBody() + } + + const currentHeight = () => { + if (!root) return 0 + const v = root.style.height + if (v && v !== "auto") { + const n = Number.parseFloat(v) + if (!Number.isNaN(n)) return n + } + return Math.max(0, root.getBoundingClientRect().height) + } + + const targetHeight = () => Math.max(0, Math.ceil(body?.getBoundingClientRect().height ?? 0)) + + const setHeight = (nextMode: "mount" | "toggle" = "mount") => { + if (!root || !open()) return + const next = targetHeight() + if (reduce()) { + springTarget = next + height.jump(next) + if (props.autoHeight === false || watch()) { + root.style.height = `${next}px` + root.style.overflow = next > 0 ? "visible" : "clip" + return + } + root.style.height = "auto" + root.style.overflow = next > 0 ? "visible" : "clip" + return + } + if (next === springTarget) return + const prev = currentHeight() + if (Math.abs(next - prev) < 1) { + springTarget = next + if (props.autoHeight === false || watch()) { + root.style.height = `${next}px` + root.style.overflow = next > 0 ? "visible" : "clip" + } + return + } + root.style.overflow = "clip" + springTarget = next + mode = nextMode + height.set(next) + } + + onMount(() => { + if (!root || !body) return + + const offChange = height.on("change", (next) => { + if (!root) return + root.style.height = `${Math.max(0, next)}px` + }) + const offStart = height.on("animationStart", () => { + if (!root) return + root.style.overflow = "clip" + root.style.willChange = "height" + root.style.contain = "layout style" + if (edgeReady()) showEdge() + }) + const offComplete = height.on("animationComplete", () => { + if (!root) return + root.style.willChange = "" + root.style.contain = "" + if (!open()) { + springTarget = 0 + root.style.height = "0px" + root.style.overflow = "clip" + return + } + const next = targetHeight() + springTarget = next + if (props.autoHeight === false || watch()) { + root.style.height = `${next}px` + root.style.overflow = next > 0 ? "visible" : "clip" + if (edgeReady()) queueEdgeHide() + return + } + root.style.height = "auto" + root.style.overflow = "visible" + if (edgeReady()) queueEdgeHide() + }) + + onCleanup(() => { + offComplete() + offStart() + offChange() + }) + + if (watch()) { + observer = new ResizeObserver(() => { + if (!open()) return + if (resizeFrame !== undefined) return + resizeFrame = requestAnimationFrame(() => { + resizeFrame = undefined + setHeight("mount") + }) + }) + observer.observe(body) + } + + if (!animated()) { + setInstant(open()) + return + } + + if (props.fade !== false) hideBody() + hideEdge(true) + + if (!open()) { + root.style.height = "0px" + root.style.overflow = "clip" + } else { + if (grow()) { + root.style.height = "0px" + root.style.overflow = "clip" + } else { + root.style.height = "auto" + root.style.overflow = "visible" + } + mountFrame = requestAnimationFrame(() => { + mountFrame = undefined + fadeBodyIn("mount") + if (grow()) setHeight("mount") + }) + } + }) + + createEffect( + on( + () => props.open, + (value) => { + if (value === undefined) return + if (!root || !body) return + if (!animateToggle() || reduce()) { + setInstant(value) + return + } + fadeAnim?.stop() + if (!value) hideEdge(true) + if (!value) { + const next = currentHeight() + if (Math.abs(next - height.get()) >= 1) { + springTarget = next + height.jump(next) + root.style.height = `${next}px` + } + if (props.fade !== false) { + fadeAnim = animate(body, { opacity: 0, filter: "blur(2px)" }, toggleSpring()) + } + root.style.overflow = "clip" + springTarget = 0 + mode = "toggle" + height.set(0) + return + } + fadeBodyIn("toggle") + setHeight("toggle") + }, + { defer: true }, + ), + ) + + createEffect(() => { + if (!edgeRef) return + edgeRef.style.height = `${edgeHeight()}px` + if (!animated() || !open() || edgeHeight() <= 0) { + hideEdge(true) + return + } + if (edge()) return + hideEdge() + }) + + createEffect(() => { + if (!root || !body) return + if (!reduce()) return + fadeAnim?.stop() + edgeAnim?.stop() + setInstant(open()) + }) + + onCleanup(() => { + stopEdgeTimer() + if (mountFrame !== undefined) cancelAnimationFrame(mountFrame) + if (resizeFrame !== undefined) cancelAnimationFrame(resizeFrame) + observer?.disconnect() + height.destroy() + fadeAnim?.stop() + edgeAnim?.stop() + edgeAnim = undefined + edgeOn = false + }) + + return ( +
+
0 ? `${gap()}px` : undefined }}> + {props.children} +
+
+
+ ) +} diff --git a/packages/kilo-ui/src/components/icon-button.css b/packages/kilo-ui/src/components/icon-button.css index 53f22522ce0..615ce842f44 100644 --- a/packages/kilo-ui/src/components/icon-button.css +++ b/packages/kilo-ui/src/components/icon-button.css @@ -12,7 +12,7 @@ opacity 120ms; &[data-variant="ghost"]:hover:not(:disabled) { - background: var(--button-ghost-hover, var(--surface-base-hover)); + background: var(--button-ghost-hover, var(--surface-base-hover, rgba(128, 128, 128, 0.2))); } &:active:not([data-disabled]) { diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css index 889b4b9c2ac..307ae9fccdd 100644 --- a/packages/kilo-ui/src/components/message-part.css +++ b/packages/kilo-ui/src/components/message-part.css @@ -12,7 +12,12 @@ } [data-slot="text-part-copy-wrapper"][data-is-turn-copy] { - display: block; + display: flex; + + [data-component="icon-button"] { + width: 20px; + height: 20px; + } } } @@ -32,6 +37,59 @@ [data-slot="message-part-title-text"] { flex-shrink: 0; } + + [data-slot="message-part-meta-line"] { + display: inline-flex; + align-items: baseline; + gap: 4px; + overflow: hidden; + white-space: nowrap; + min-width: 0; + flex-shrink: 1; + + &.clickable { + cursor: pointer; + transition: color 0.15s ease; + + &:hover { + color: var(--text-base); + } + } + } + + [data-slot="message-part-title-filename"] { + flex-shrink: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + direction: rtl; + text-align: left; + } + + [data-slot="message-part-directory-inline"] { + color: var(--text-weak); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + direction: rtl; + text-align: left; + flex-shrink: 1; + min-width: 0; + } +} + +/* Prevent long filenames in apply-patch accordion from hiding diff changes */ +[data-component="accordion"][data-scope="apply-patch"] { + [data-slot="apply-patch-filename"] { + flex-shrink: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + direction: rtl; + text-align: left; + } } /* Task tool child-session tool list (v1.0.25 style) */ @@ -92,26 +150,24 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { margin-bottom: 0px; } -/* Remove the empty space below user message bubbles. - * The upstream copy wrapper is a normal-flow block with min-height + margin, - * so it reserves ~28px even when invisible. Override it to be absolutely - * positioned over the bottom-right corner of the bubble — zero layout impact - * when hidden, overlays on hover exactly like the text-part copy button. */ +/* User message copy button: collapse wrapper when idle, show on hover. + * The wrapper must be tall enough to fully contain the button (20px) + * so that hovering the button keeps [data-component="user-message"] + * hovered — otherwise :hover is lost and pointer-events/opacity revert. */ [data-component="user-message"] { - position: relative; - [data-slot="user-message-copy-wrapper"] { - position: absolute; - top: 4px; - right: 4px; - bottom: auto; - min-height: unset; + min-height: 0; + height: 20px; margin-top: 0; - width: auto; - /* hide meta text; only the icon-button matters in the sidebar */ + [data-slot="user-message-meta-wrap"] { display: none; } + + [data-component="icon-button"] { + width: 20px; + height: 20px; + } } } @@ -119,7 +175,9 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { padding: 8px; } -/* Reasoning block: visually distinct from normal agent output */ +/* Reasoning block: visually distinct from normal agent output. + While streaming: open with fixed-height scrollable window. + When done: auto-collapses; user can click to reopen. */ [data-component="reasoning-part"] { width: 100%; border-left: 2px solid var(--border-weak-base); @@ -131,12 +189,16 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { } [data-slot="collapsible-trigger"] { - height: 28px; + height: 36px; padding: 0 8px; gap: 6px; background: var(--surface-inset-base); border-radius: 0; cursor: pointer; + + &:hover { + background-color: var(--surface-inset-base-hover, var(--vscode-list-hoverBackground)); + } } [data-slot="reasoning-header"] { @@ -178,4 +240,72 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { } } } + + /* Collapse/expand animation via Kobalte's CSS variable. + Uses grid trick: the outer wrapper transitions grid-template-rows + between 0fr (collapsed) and 1fr (expanded) so the content smoothly + collapses without needing to know the pixel height up front. */ + [data-slot="collapsible-content"] { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows 250ms ease-out; + overflow: hidden; + + > * { + overflow: hidden; + } + + &[data-expanded] { + grid-template-rows: 1fr; + } + } + + /* Streaming state: fixed-height window with auto-scroll */ + &[data-streaming] { + [data-slot="reasoning-content"] { + max-height: 120px; + overflow-y: auto; + scroll-behavior: smooth; + mask-image: linear-gradient(to bottom, transparent 0%, black 12px, black 85%, transparent 100%); + -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 12px, black 85%, transparent 100%); + } + + /* Pulse the brain icon while streaming */ + [data-slot="reasoning-header"] [data-component="icon"] { + animation: reasoning-pulse 2s ease-in-out infinite; + } + } +} + +@keyframes reasoning-pulse { + 0%, + 100% { + opacity: 0.5; + } + 50% { + opacity: 1; + } +} + +[data-component="tool-hint"] { + display: flex; + align-items: start; + gap: 6px; + padding: 4px 8px; + border-left: 2px solid var(--border-weak-base); + + [data-component="icon"] { + flex-shrink: 0; + color: var(--icon-weak-base); + margin-top: 1px; + } + + [data-slot="tool-hint-message"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-style: italic; + color: var(--text-weak); + opacity: 0.9; + line-height: var(--line-height-large); + } } diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx index 157e015f9e8..f41d3cbd8ed 100644 --- a/packages/kilo-ui/src/components/message-part.tsx +++ b/packages/kilo-ui/src/components/message-part.tsx @@ -1,27 +1,1281 @@ -export * from "@opencode-ai/ui/message-part" +import { + Component, + createEffect, + createMemo, + createSignal, + For, + Match, + on, + onCleanup, + Show, + Switch, + type JSX, +} from "solid-js" +import stripAnsi from "strip-ansi" +import { createStore } from "solid-js/store" +import { Dynamic } from "solid-js/web" +import { + AgentPart, + AssistantMessage, + FilePart, + Message as MessageType, + Part as PartType, + ReasoningPart, + TextPart, + ToolPart, + UserMessage, + Todo, + QuestionAnswer, + QuestionInfo, +} from "@kilocode/sdk/v2" +import { useData } from "../context" +import { useFileComponent } from "../context/file" +import { useDialog } from "../context/dialog" +import { type UiI18n, useI18n } from "../context/i18n" +import { GenericTool, BasicTool } from "./basic-tool" +import { Accordion } from "./accordion" +import { StickyAccordionHeader } from "./sticky-accordion-header" +import { Card } from "./card" +import { Collapsible } from "./collapsible" +import { FileIcon } from "./file-icon" +import { Icon } from "./icon" +import { Checkbox } from "./checkbox" +import { DiffChanges } from "./diff-changes" +import { Markdown } from "./markdown" +import { ImagePreview } from "./image-preview" +import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path" +import { checksum } from "@opencode-ai/util/encode" +import { Tooltip } from "./tooltip" +import { IconButton } from "./icon-button" +import { TextShimmer } from "@opencode-ai/ui/text-shimmer" +import { GrowBox } from "./grow-box" +import { COLLAPSIBLE_SPRING } from "./motion" +import { busy, createThrottledValue, useToolFade, useContextToolPending } from "./tool-utils" +import { ContextToolGroupHeader, ContextToolExpandedList, ContextToolRollingResults } from "./context-tool-results" +import { ShellRollingResults } from "./shell-rolling-results" +import { extractFilePathFromHref } from "../file-path" -import { Show, createSignal } from "solid-js" -import { PART_MAPPING } from "@opencode-ai/ui/message-part" -import { Collapsible } from "@opencode-ai/ui/collapsible" -import { Icon } from "@opencode-ai/ui/icon" -import { Markdown } from "@opencode-ai/ui/markdown" -import { useI18n } from "@opencode-ai/ui/context/i18n" -import type { ReasoningPart } from "@kilocode/sdk/v2" -import type { MessagePartProps } from "@opencode-ai/ui/message-part" +// Windows CLI tools (e.g. winget) use \r to overwrite progress bars in-place. +// Without this, every progress frame renders as a separate visual line. +function processCarriageReturns(input: string): string { + // Normalize \r\n to \n first so CRLF line endings aren't treated as overwrites + const normalized = input.replace(/\r\n/g, "\n") + return normalized + .split("\n") + .map((line) => { + if (!line.includes("\r")) return line + const parts = line.split("\r") + // A trailing \r produces an empty last segment — preserve the previous visible frame + const last = parts[parts.length - 1] + if (last !== "") return last + for (let i = parts.length - 2; i >= 0; i--) { + if (parts[i] !== "") return parts[i] + } + return "" + }) + .join("\n") +} -// Override: collapsible reasoning block with brain icon + label -// Replaces the upstream flat markdown render with a clearly distinguished, collapsed-by-default block -PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProps) { - const part = props.part as unknown as ReasoningPart +interface Diagnostic { + range: { + start: { line: number; character: number } + end: { line: number; character: number } + } + message: string + severity?: number +} + +function getDiagnostics( + diagnosticsByFile: Record | undefined, + filePath: string | undefined, +): Diagnostic[] { + if (!diagnosticsByFile || !filePath) return [] + const diagnostics = diagnosticsByFile[filePath] ?? [] + return diagnostics.filter((d) => d.severity === 1).slice(0, 3) +} + +function DiagnosticsDisplay(props: { diagnostics: Diagnostic[] }): JSX.Element { const i18n = useI18n() - const [open, setOpen] = createSignal(false) - // Filter out redacted reasoning chunks from OpenRouter (encrypted reasoning data appears as [REDACTED]) - const text = () => (part.text ?? "").replace("[REDACTED]", "").trim() + return ( + 0}> +
+ + {(diagnostic) => ( +
+ {i18n.t("ui.messagePart.diagnostic.error")} + + [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}] + + {diagnostic.message} +
+ )} +
+
+
+ ) +} + +export interface MessagePartProps { + part: PartType + message: MessageType + hideDetails?: boolean + defaultOpen?: boolean + showAssistantCopyPartID?: string | null + showTurnDiffSummary?: boolean + turnDiffSummary?: () => JSX.Element + animate?: boolean + working?: boolean +} + +export type PartComponent = Component + +export const PART_MAPPING: Record = {} + +function relativizeProjectPath(path: string, directory?: string) { + if (!path) return "" + if (!directory) return path + if (directory === "/") return path + if (directory === "\\") return path + if (path === directory) return "" + + const separator = directory.includes("\\") ? "\\" : "/" + const prefix = directory.endsWith(separator) ? directory : directory + separator + if (!path.startsWith(prefix)) return path + return path.slice(directory.length) +} + +function getDirectory(path: string | undefined) { + const data = useData() + return relativizeProjectPath(_getDirectory(path), data.directory) +} + +import type { IconProps } from "./icon" + +export type ToolInfo = { + icon: IconProps["name"] + title: string + subtitle?: string +} + +function agentTitle(i18n: UiI18n, type?: string) { + if (!type) return i18n.t("ui.tool.agent.default") + return i18n.t("ui.tool.agent", { type }) +} + +export function getToolInfo(tool: string, input: any = {}): ToolInfo { + const i18n = useI18n() + switch (tool) { + case "read": + return { + icon: "glasses", + title: i18n.t("ui.tool.read"), + subtitle: input.filePath ? getFilename(input.filePath) : undefined, + } + case "list": + return { + icon: "bullet-list", + title: i18n.t("ui.tool.list"), + subtitle: input.path ? getFilename(input.path) : undefined, + } + case "glob": + return { + icon: "magnifying-glass-menu", + title: i18n.t("ui.tool.glob"), + subtitle: input.pattern, + } + case "grep": + return { + icon: "magnifying-glass-menu", + title: i18n.t("ui.tool.grep"), + subtitle: input.pattern, + } + case "webfetch": + return { + icon: "window-cursor", + title: i18n.t("ui.tool.webfetch"), + subtitle: input.url, + } + case "websearch": + return { + icon: "window-cursor", + title: i18n.t("ui.tool.websearch"), + subtitle: input.query, + } + case "codesearch": + return { + icon: "code", + title: i18n.t("ui.tool.codesearch"), + subtitle: input.query, + } + case "task": { + const type = + typeof input.subagent_type === "string" && input.subagent_type + ? input.subagent_type[0]!.toUpperCase() + input.subagent_type.slice(1) + : undefined + return { + icon: "task", + title: agentTitle(i18n, type), + subtitle: input.description, + } + } + case "bash": + return { + icon: "console", + title: i18n.t("ui.tool.shell"), + subtitle: input.description, + } + case "edit": + return { + icon: "code-lines", + title: i18n.t("ui.messagePart.title.edit"), + subtitle: input.filePath ? getFilename(input.filePath) : undefined, + } + case "write": + return { + icon: "code-lines", + title: i18n.t("ui.messagePart.title.write"), + subtitle: input.filePath ? getFilename(input.filePath) : undefined, + } + case "apply_patch": + return { + icon: "code-lines", + title: i18n.t("ui.tool.patch"), + subtitle: input.files?.length + ? `${input.files.length} ${i18n.t(input.files.length > 1 ? "ui.common.file.other" : "ui.common.file.one")}` + : undefined, + } + case "todowrite": + return { + icon: "checklist", + title: i18n.t("ui.tool.todos"), + } + case "todoread": + return { + icon: "checklist", + title: i18n.t("ui.tool.todos.read"), + } + case "question": + return { + icon: "bubble-5", + title: i18n.t("ui.tool.questions"), + } + case "skill": + return { + icon: "brain", + title: i18n.t("ui.tool.skill"), + subtitle: typeof input.name === "string" ? input.name : undefined, + } + default: + return { + icon: "mcp", + title: tool, + } + } +} + +function urls(text: string | undefined) { + if (!text) return [] + const seen = new Set() + return [...text.matchAll(/https?:\/\/[^\s<>"'`)\]]+/g)] + .map((item) => item[0].replace(/[),.;:!?]+$/g, "")) + .filter((item) => { + if (seen.has(item)) return false + seen.add(item) + return true + }) +} + +const CONTEXT_GROUP_TOOLS = new Set(["read", "glob", "grep", "list"]) +const HIDDEN_TOOLS = new Set(["todowrite", "todoread"]) + +function list(value: T[] | undefined | null, fallback: T[]) { + if (Array.isArray(value)) return value + return fallback +} + +function createGroupOpenState() { + const [state, setState] = createStore>({}) + const read = (key?: string, collapse?: boolean) => { + if (!key) return true + const value = state[key] + if (value !== undefined) return value + return !collapse + } + const controlled = (key?: string) => { + if (!key) return false + return state[key] !== undefined + } + const write = (key: string, value: boolean) => { + setState(key, value) + } + return { read, controlled, write } +} + +function renderable(part: PartType, showReasoningSummaries = true) { + if (part.type === "tool") { + if (HIDDEN_TOOLS.has(part.tool)) return false + if (part.tool === "question") return part.state.status !== "pending" && part.state.status !== "running" + return true + } + if (part.type === "text") return !!part.text?.trim() + if (part.type === "reasoning") return showReasoningSummaries && !!part.text?.trim() + return !!PART_MAPPING[part.type] +} + +function toolDefaultOpen(tool: string, shell = false, edit = false) { + if (tool === "bash") return shell + if (tool === "edit" || tool === "write") return edit + if (tool === "apply_patch") return false +} + +function partDefaultOpen(part: PartType, shell = false, edit = false) { + if (part.type !== "tool") return + return toolDefaultOpen(part.tool, shell, edit) +} + +function PartGrow(props: { + children: JSX.Element + animate?: boolean + animateToggle?: boolean + gap?: number + fade?: boolean + edge?: boolean + edgeHeight?: number + edgeOpacity?: number + edgeIdle?: number + edgeFade?: number + edgeRise?: number + grow?: boolean + watch?: boolean + open?: boolean + spring?: import("./motion").SpringConfig + toggleSpring?: import("./motion").SpringConfig +}) { + return ( + + {props.children} + + ) +} + +export function AssistantParts(props: { + messages: AssistantMessage[] + showAssistantCopyPartID?: string | null + showTurnDiffSummary?: boolean + turnDiffSummary?: () => JSX.Element + working?: boolean + showReasoningSummaries?: boolean + shellToolDefaultOpen?: boolean + editToolDefaultOpen?: boolean + animate?: boolean +}) { + const data = useData() + const emptyParts: PartType[] = [] + const groupState = createGroupOpenState() + const grouped = createMemo(() => { + const keys: string[] = [] + const items: Record< + string, + | { + type: "part" + part: PartType + message: AssistantMessage + context?: boolean + groupKey?: string + afterTool?: boolean + groupTail?: boolean + groupParts?: { part: ToolPart; message: AssistantMessage }[] + } + | { + type: "context" + groupKey: string + parts: { part: ToolPart; message: AssistantMessage }[] + tail: boolean + afterTool: boolean + } + > = {} + const push = (key: string, item: (typeof items)[string]) => { + keys.push(key) + items[key] = item + } + const id = (part: PartType) => { + if (part.type === "tool") return part.callID || part.id + return part.id + } + const parts = props.messages.flatMap((message) => { + const filtered = list(data.store.part?.[message.id], emptyParts).filter((part) => + renderable(part, props.showReasoningSummaries ?? true), + ) + // Ensure reasoning parts appear before text parts within each message. + // During streaming the reasoning part may arrive after the text part + // in the store (SSE order), but visually reasoning always precedes text. + const reasoning: typeof filtered = [] + const rest: typeof filtered = [] + for (const p of filtered) { + if (p.type === "reasoning") reasoning.push(p) + else rest.push(p) + } + return [...reasoning, ...rest].map((part) => ({ message, part })) + }) + + let start = -1 + + const flush = (end: number, tail: boolean, afterTool: boolean) => { + if (start < 0) return + const group = parts + .slice(start, end + 1) + .filter((entry): entry is { part: ToolPart; message: AssistantMessage } => isContextGroupTool(entry.part)) + if (!group.length) { + start = -1 + return + } + const groupKey = `context:${group[0].message.id}:${id(group[0].part)}` + push(groupKey, { + type: "context", + groupKey, + parts: group, + tail, + afterTool, + }) + group.forEach((entry) => { + push(`part:${entry.message.id}:${id(entry.part)}`, { + type: "part", + part: entry.part, + message: entry.message, + context: true, + groupKey, + afterTool, + groupTail: tail, + groupParts: group, + }) + }) + start = -1 + } + parts.forEach((item, index) => { + if (isContextGroupTool(item.part)) { + if (start < 0) start = index + return + } + + flush(index - 1, false, (item as { part: PartType }).part.type === "tool") + push(`part:${item.message.id}:${id(item.part)}`, { type: "part", part: item.part, message: item.message }) + }) + + flush(parts.length - 1, true, false) + return { keys, items } + }) + + const last = createMemo(() => grouped().keys.at(-1)) return ( - -
- +
+ + {(key) => { + const item = createMemo(() => grouped().items[key]) + const ctx = createMemo(() => { + const value = item() + if (!value) return + if (value.type !== "context") return + return value + }) + const part = createMemo(() => { + const value = item() + if (!value) return + if (value.type !== "part") return + return value + }) + const tail = createMemo(() => last() === key) + const tool = createMemo(() => { + const value = part() + if (!value) return false + return value.part.type === "tool" + }) + const context = createMemo(() => !!part()?.context) + const contextSpring = createMemo(() => { + const entry = part() + if (!entry?.context) return undefined + if (!groupState.controlled(entry.groupKey)) return undefined + return COLLAPSIBLE_SPRING + }) + const contextOpen = createMemo(() => { + const value = ctx() + if (value) return groupState.read(value.groupKey, true) + return groupState.read(part()?.groupKey, true) + }) + const visible = createMemo(() => { + if (!context()) return true + if (ctx()) return true + return false + }) + + const turnSummary = createMemo(() => { + const value = part() + if (!value) return false + if (value.part.type !== "text") return false + if (!props.showTurnDiffSummary) return false + return props.showAssistantCopyPartID === value.part.id + }) + const fade = createMemo(() => { + if (ctx()) return true + return tool() + }) + const edge = createMemo(() => { + const entry = part() + if (!entry) return false + if (entry.part.type !== "text") return false + if (!props.working) return false + return tail() + }) + const watch = createMemo(() => !context() && !tool() && tail() && !turnSummary()) + const ctxPartsCache = new Map() + let ctxPartsPrev: ToolPart[] = [] + const ctxParts = createMemo(() => { + const parts = ctx()?.parts ?? [] + if (parts.length === 0 && ctxPartsPrev.length > 0) return ctxPartsPrev + const result: ToolPart[] = [] + for (const item of parts) { + const k = item.part.callID || item.part.id + const cached = ctxPartsCache.get(k) + if (cached) { + result.push(cached) + } else { + ctxPartsCache.set(k, item.part) + result.push(item.part) + } + } + ctxPartsPrev = result + return result + }) + const ctxPending = useContextToolPending(ctxParts, () => !!(props.working && ctx()?.tail)) + const shell = createMemo(() => { + const value = part() + if (!value) return + if (value.part.type !== "tool") return + if (value.part.tool !== "bash") return + return value.part + }) + const kind = createMemo(() => { + if (ctx()) return "context" + if (shell()) return "shell" + const value = part() + if (!value) return "part" + return value.part.type + }) + const shown = createMemo(() => { + if (ctx()) return true + if (shell()) return true + const entry = part() + if (!entry) return false + return !entry.context + }) + const partGrowProps = () => ({ + animate: props.animate, + gap: 0, + fade: fade(), + edge: edge(), + edgeHeight: 20, + edgeOpacity: 0.95, + edgeIdle: 100, + edgeFade: 0.6, + edgeRise: 0.1, + grow: true, + watch: watch(), + animateToggle: true, + open: visible(), + toggleSpring: contextSpring(), + }) + return ( + +
+ + {(entry) => ( + <> + + groupState.write(entry().groupKey, value)} + /> + + + + + )} + + + {(value) => ( + + )} + + + {(entry) => ( + + +
+ +
+
+
+ )} +
+
+
+ ) + }} +
+
+ ) +} + +function isContextGroupTool(part: PartType): part is ToolPart { + return part.type === "tool" && CONTEXT_GROUP_TOOLS.has(part.tool) +} + +function ExaOutput(props: { output?: string }) { + const links = createMemo(() => urls(props.output)) + + return ( + 0}> +
+
+ + {(url) => ( + event.stopPropagation()} + > + {url} + + )} + +
+
+
+ ) +} + +export function registerPartComponent(type: string, component: PartComponent) { + PART_MAPPING[type] = component +} + +export function UserMessageDisplay(props: { + message: UserMessage + parts: PartType[] + interrupted?: boolean + animate?: boolean + queued?: boolean + onRevert?: () => void +}) { + const data = useData() + const dialog = useDialog() + const i18n = useI18n() + const [copied, setCopied] = createSignal(false) + + const textPart = createMemo( + () => props.parts?.find((p) => p.type === "text" && !(p as TextPart).synthetic) as TextPart | undefined, + ) + + const text = createMemo(() => textPart()?.text || "") + + const files = createMemo(() => (props.parts?.filter((p) => p.type === "file") as FilePart[]) ?? []) + + const attachments = createMemo(() => + files()?.filter((f) => { + const mime = f.mime + return mime.startsWith("image/") || mime === "application/pdf" + }), + ) + + const inlineFiles = createMemo(() => + files().filter((f) => { + const mime = f.mime + return !mime.startsWith("image/") && mime !== "application/pdf" && f.source?.text?.start !== undefined + }), + ) + + const agents = createMemo(() => (props.parts?.filter((p) => p.type === "agent") as AgentPart[]) ?? []) + + const model = createMemo(() => { + const providerID = props.message.model?.providerID + const modelID = props.message.model?.modelID + if (!providerID || !modelID) return "" + const match = data.store.provider?.all?.find((p) => p.id === providerID) + return match?.models?.[modelID]?.name ?? modelID + }) + + const stamp = createMemo(() => { + const created = props.message.time?.created + if (typeof created !== "number") return "" + const date = new Date(created) + const hours = date.getHours() + const hour12 = hours % 12 || 12 + const minute = String(date.getMinutes()).padStart(2, "0") + return `${hour12}:${minute} ${hours < 12 ? "AM" : "PM"}` + }) + + const metaHead = createMemo(() => { + const agent = props.message.agent + const items = [agent ? agent[0]?.toUpperCase() + agent.slice(1) : "", model()] + return items.filter((x) => !!x).join("\u00A0\u00B7\u00A0") + }) + + const metaTail = createMemo(() => { + const items = [stamp(), props.interrupted ? i18n.t("ui.message.interrupted") : ""] + return items.filter((x) => !!x).join("\u00A0\u00B7\u00A0") + }) + + const openImagePreview = (url: string, alt?: string) => { + dialog.show(() => ) + } + + const handleCopy = async () => { + const content = text() + if (!content) return + await navigator.clipboard.writeText(content) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + return ( + +
+ 0}> +
+ + {(file) => ( +
{ + if (file.mime.startsWith("image/") && file.url) { + openImagePreview(file.url, file.filename) + } + }} + > + + +
+ } + > + {file.filename + +
+ )} + +
+ + + <> +
+
+ +
+ +
+ +
+
+
+ +
+ + + + + {metaHead()} + + + + + {"\u00A0\u00B7\u00A0"} + + + + + {metaTail()} + + + + + + + e.preventDefault()} + onClick={(event) => { + event.stopPropagation() + props.onRevert?.() + }} + aria-label={i18n.t("ui.message.revert")} + /> + + + + e.preventDefault()} + onClick={(event) => { + event.stopPropagation() + handleCopy() + }} + aria-label={copied() ? i18n.t("ui.message.copied") : i18n.t("ui.message.copyMessage")} + /> + +
+ +
+
+ + ) +} + +type HighlightSegment = { text: string; type?: "file" | "agent" } + +function HighlightedText(props: { text: string; references: FilePart[]; agents: AgentPart[] }) { + const segments = createMemo(() => { + const text = props.text + + const allRefs: { start: number; end: number; type: "file" | "agent" }[] = [ + ...props.references + .filter((r) => r.source?.text?.start !== undefined && r.source?.text?.end !== undefined) + .map((r) => ({ start: r.source!.text!.start, end: r.source!.text!.end, type: "file" as const })), + ...props.agents + .filter((a) => a.source?.start !== undefined && a.source?.end !== undefined) + .map((a) => ({ start: a.source!.start, end: a.source!.end, type: "agent" as const })), + ].sort((a, b) => a.start - b.start) + + const result: HighlightSegment[] = [] + let lastIndex = 0 + + for (const ref of allRefs) { + if (ref.start < lastIndex) continue + + if (ref.start > lastIndex) { + result.push({ text: text.slice(lastIndex, ref.start) }) + } + + result.push({ text: text.slice(ref.start, ref.end), type: ref.type }) + lastIndex = ref.end + } + + if (lastIndex < text.length) { + result.push({ text: text.slice(lastIndex) }) + } + + return result + }) + + return {(segment) => {segment.text}} +} + +export function Part(props: MessagePartProps) { + const component = createMemo(() => PART_MAPPING[props.part.type]) + return ( + + + + ) +} + +export interface ToolProps { + input: Record + metadata: Record + tool: string + partID?: string + callID?: string + output?: string + status?: string + hideDetails?: boolean + defaultOpen?: boolean + forceOpen?: boolean + locked?: boolean + animate?: boolean + reveal?: boolean +} + +export type ToolComponent = Component + +const state: Record< + string, + { + name: string + render?: ToolComponent + } +> = {} + +export function registerTool(input: { name: string; render?: ToolComponent }) { + state[input.name] = input + return input +} + +export function getTool(name: string) { + return state[name]?.render +} + +export const ToolRegistry = { + register: registerTool, + render: getTool, +} + +function ToolFileAccordion(props: { path: string; actions?: JSX.Element; children: JSX.Element }) { + const value = createMemo(() => props.path || "tool-file") + + return ( + + + + +
+
+ +
+ + {`\u202A${getDirectory(props.path)}\u202C`} + + {getFilename(props.path)} +
+
+
+ {props.actions} + +
+
+
+
+ {props.children} +
+
+ ) +} + +// GenericTool (upstream) does not render output; this override does. +// When hideDetails is true, render as a row (no content), otherwise as a panel with markdown output. +function McpTool(props: ToolProps) { + return ( + } + > + + + {(output) => ( +
+ +
+ )} +
+
+
+ ) +} + +PART_MAPPING["tool"] = function ToolPartDisplay(props) { + const i18n = useI18n() + const part = props.part as ToolPart + const hideQuestion = createMemo(() => part.tool === "question" && busy(part.state.status)) + + const emptyInput: Record = {} + const emptyMetadata: Record = {} + + const input = () => part.state?.input ?? emptyInput + // @ts-expect-error + const partMetadata = () => part.state?.metadata ?? emptyMetadata + + const render = createMemo(() => ToolRegistry.render(part.tool) ?? McpTool) + + return ( + +
+ + + {(error) => { + const cleaned = error().replace("Error: ", "") + if (part.tool === "question" && cleaned.includes("dismissed this question")) { + return ( +
+ + {i18n.t("ui.messagePart.questions.dismissed")} + +
+ ) + } + const hint = + cleaned.includes("before overwriting it. Use the Read tool first") || + cleaned.includes("has been modified since it was last read") || + cleaned.includes("oldString and newString are identical") || + cleaned.includes("must match exactly, including whitespace") || + cleaned.includes("Found multiple matches for oldString") + if (hint) { + return ( +
+ + {cleaned} +
+ ) + } + const [title, ...rest] = cleaned.split(": ") + return ( + +
+ + + +
+
{title}
+ {rest.join(": ")} +
+
+ + {cleaned} + +
+
+
+ ) + }} +
+ + + +
+
+
+ ) +} + +PART_MAPPING["compaction"] = function CompactionPartDisplay() { + const i18n = useI18n() + return ( +
+
+ + + {i18n.t("ui.messagePart.compaction")} + + +
+
+ ) +} + +PART_MAPPING["text"] = function TextPartDisplay(props) { + const data = useData() + const part = () => props.part as TextPart + + const displayText = () => (part().text ?? "").trim() + const throttledText = createThrottledValue(displayText) + const summary = createMemo(() => { + if (props.message.role !== "assistant") return + if (!props.showTurnDiffSummary) return + if (props.showAssistantCopyPartID !== part().id) return + return props.turnDiffSummary + }) + + const handleMarkdownClick = (e: MouseEvent) => { + if (!data.openFile) return + const target = e.target + if (!(target instanceof HTMLElement)) return + // Handle .file-link code spans (e.g. `src/foo.ts:42`) + const fileLink = target.closest(".file-link[data-file-path]") + if (fileLink) { + const path = fileLink.getAttribute("data-file-path") + if (!path) return + const lineAttr = fileLink.getAttribute("data-file-line") + const colAttr = fileLink.getAttribute("data-file-col") + const line = lineAttr ? parseInt(lineAttr, 10) : undefined + const column = colAttr ? parseInt(colAttr, 10) : undefined + data.openFile(path, line, column) + return + } + // Handle markdown links whose href looks like a relative file path + const anchor = target.closest("a.external-link") as HTMLAnchorElement | null + if (anchor) { + const href = anchor.getAttribute("href") + if (!href) return + const filePath = extractFilePathFromHref(href) + if (!filePath) return + e.preventDefault() + data.openFile(filePath) + } + } + + return ( + +
+
+ +
+ + {(render) => ( + +
{render()()}
+
+ )} +
+
+
+ ) +} + +// Track part IDs that have been rendered while streaming. +// Persists across component instances so that when reasoning-end replaces the +// store object (causing to recreate the component) the new instance +// knows the part was just streaming and can animate the collapse. +const streamed = new Set() +// Tracks parts that have already been auto-collapsed once, so component +// recreation (from store updates while other parts stream) won't collapse again. +const autocollapsed = new Set() + +// Overrides upstream flat markdown render with streaming reasoning block + auto-collapse. +// Also filters encrypted reasoning data from OpenRouter that appears as [REDACTED]. +PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProps) { + const i18n = useI18n() + + const text = () => { + const p = props.part as unknown as ReasoningPart + return (p.text ?? "").replace("[REDACTED]", "").trim() + } + + // Throttle markdown re-renders during streaming + const display = createThrottledValue(text) + + // time.end is set by the processor on reasoning-end. + // v1 parts lack time entirely → treat as historical. + const done = () => { + const t = (props.part as any).time + return !t || !!t.end + } + + const id = (props.part as any).id as string + + // Check before adding — order matters + const was = streamed.has(id) + if (!done()) streamed.add(id) + + // Streaming → open. Just finished (was streaming, now done) → open briefly + // then collapse. Historical → collapsed from the start. + const [open, setOpen] = createSignal(!done() || was) + + // Auto-collapse once when reasoning finishes (streaming → done transition). + // Collapses immediately so the grid transition runs in sync with the + // streaming-height removal. Module-level Set prevents re-triggering on + // component recreation or when the user manually reopens. + createEffect(() => { + if (done() && open() && !autocollapsed.has(id)) { + autocollapsed.add(id) + setOpen(false) + } + }) + + onCleanup(() => { + if (done()) streamed.delete(id) + }) + + // Auto-scroll the content container while streaming + let ref: HTMLDivElement | undefined + createEffect(() => { + display() + if (!done() && ref) { + ref.scrollTop = ref.scrollHeight + } + }) + + return ( + +
+
@@ -30,8 +1284,8 @@ PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProp -
- +
+
@@ -39,3 +1293,1068 @@ PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProp ) } + +function useToolReveal(pending: () => boolean, animate?: () => boolean) { + const enabled = () => animate?.() ?? true + const [live, setLive] = createSignal(pending() || enabled()) + createEffect(() => { + if (pending()) setLive(true) + }) + return () => enabled() && live() +} + +function WebfetchMeta(props: { url: string; animate?: boolean }) { + let ref: HTMLSpanElement | undefined + useToolFade(() => ref, { wipe: true, animate: props.animate }) + + return ( + + event.stopPropagation()} + > + {props.url} + +
+ +
+
+ ) +} + +function TaskLink(props: { href: string; text: string; onClick: (e: MouseEvent) => void; animate?: boolean }) { + let ref: HTMLAnchorElement | undefined + useToolFade(() => ref, { wipe: true, animate: props.animate }) + + return ( + + {props.text} + + ) +} + +function ToolText(props: { text: string; delay?: number; animate?: boolean }) { + let ref: HTMLSpanElement | undefined + useToolFade(() => ref, { delay: props.delay, wipe: true, animate: props.animate }) + + return ( + + {props.text} + + ) +} + +function ToolLoadedFile(props: { text: string; animate?: boolean; onClick?: () => void }) { + let ref: HTMLDivElement | undefined + useToolFade(() => ref, { delay: 0.02, wipe: true, animate: props.animate }) + + return ( + +
+ + {props.text} +
+
+ ) +} + +function ToolTriggerRow(props: { + title: string + pending: boolean + subtitle?: string + args?: string[] + action?: JSX.Element + animate?: boolean + revealOnMount?: boolean +}) { + const reveal = useToolReveal( + () => props.pending, + () => props.animate !== false, + ) + const detail = createMemo(() => [props.subtitle, ...(props.args ?? [])].filter((x): x is string => !!x).join(" ")) + const detailAnimate = createMemo(() => { + if (props.animate === false) return false + if (props.revealOnMount) return true + if (!props.pending && !reveal()) return true + return reveal() + }) + + return ( +
+
+ + + + {(text) => } +
+ {props.action} +
+ ) +} + +type DiffValue = { additions: number; deletions: number } | { additions: number; deletions: number }[] + +function ToolMetaLine(props: { + filename: string + path?: string + changes?: DiffValue + delay?: number + animate?: boolean + soft?: boolean + onClick?: (e: MouseEvent) => void +}) { + let ref: HTMLSpanElement | undefined + useToolFade(() => ref, { delay: props.delay ?? 0.02, wipe: true, animate: props.animate }) + + return ( + + {props.filename} + + {props.path} + + {(changes) => } + + ) +} + +function ToolChanges(props: { changes: DiffValue; animate?: boolean }) { + let ref: HTMLDivElement | undefined + useToolFade(() => ref, { delay: 0.04, animate: props.animate }) + + return ( +
+ +
+ ) +} + +function ShellText(props: { text: string; animate?: boolean }) { + let ref: HTMLSpanElement | undefined + useToolFade(() => ref, { wipe: true, animate: props.animate }) + + return ( + + + + {props.text} + + + + ) +} + +ToolRegistry.register({ + name: "read", + render(props) { + const data = useData() + const i18n = useI18n() + const args: string[] = [] + if (props.input.offset) args.push("offset=" + props.input.offset) + if (props.input.limit) args.push("limit=" + props.input.limit) + const loaded = createMemo(() => { + const value = props.metadata.loaded + if (!value || !Array.isArray(value)) return [] + return value.filter((p): p is string => typeof p === "string") + }) + const pending = createMemo(() => busy(props.status)) + return ( + <> + data.openFile!(props.input.filePath) : undefined + } + trigger={ + + } + /> + + {(filepath) => ( + data.openFile!(filepath) : undefined} + /> + )} + + + ) + }, +}) + +ToolRegistry.register({ + name: "list", + render(props) { + const i18n = useI18n() + const pending = createMemo(() => busy(props.status)) + return ( + + } + > + + {(output) => ( +
+ +
+ )} +
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "glob", + render(props) { + const i18n = useI18n() + const pending = createMemo(() => busy(props.status)) + return ( + + +
+ )} + + + ) + }, +}) + +ToolRegistry.register({ + name: "grep", + render(props) { + const i18n = useI18n() + const args: string[] = [] + if (props.input.pattern) args.push("pattern=" + props.input.pattern) + if (props.input.include) args.push("include=" + props.input.include) + const pending = createMemo(() => busy(props.status)) + return ( + + } + > + + {(output) => ( +
+ +
+ )} +
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "webfetch", + render(props) { + const i18n = useI18n() + const pending = createMemo(() => busy(props.status)) + const reveal = useToolReveal(pending, () => props.reveal !== false) + const url = createMemo(() => { + const value = props.input.url + if (typeof value !== "string") return "" + return value + }) + return ( + +
+ + + + {(value) => } +
+
+ } + /> + ) + }, +}) + +ToolRegistry.register({ + name: "websearch", + render(props) { + const i18n = useI18n() + const query = createMemo(() => { + const value = props.input.query + if (typeof value !== "string") return "" + return value + }) + + return ( + + + + ) + }, +}) + +ToolRegistry.register({ + name: "codesearch", + render(props) { + const i18n = useI18n() + const query = createMemo(() => { + const value = props.input.query + if (typeof value !== "string") return "" + return value + }) + + return ( + + + + ) + }, +}) + +ToolRegistry.register({ + name: "task", + render(props) { + const data = useData() + const i18n = useI18n() + const childSessionId = () => props.metadata.sessionId as string | undefined + const type = createMemo(() => { + const raw = props.input.subagent_type + if (typeof raw !== "string" || !raw) return undefined + return raw[0]!.toUpperCase() + raw.slice(1) + }) + const title = createMemo(() => agentTitle(i18n, type())) + const description = createMemo(() => { + const value = props.input.description + if (typeof value === "string") return value + return undefined + }) + const running = createMemo(() => busy(props.status)) + const reveal = useToolReveal(running, () => props.reveal !== false) + + const href = createMemo(() => { + const sessionId = childSessionId() + if (!sessionId) return + + const direct = data.sessionHref?.(sessionId) + if (direct) return direct + + if (typeof window === "undefined") return + const path = window.location.pathname + const idx = path.indexOf("/session") + if (idx === -1) return + return `${path.slice(0, idx)}/session/${sessionId}` + }) + + const handleLinkClick = (e: MouseEvent) => { + const sessionId = childSessionId() + const url = href() + if (!sessionId || !url) return + + e.stopPropagation() + + if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return + + const nav = data.navigateToSession + if (!nav || typeof window === "undefined") return + + e.preventDefault() + const before = window.location.pathname + window.location.search + window.location.hash + nav(sessionId) + setTimeout(() => { + const after = window.location.pathname + window.location.search + window.location.hash + if (after === before) window.location.assign(url) + }, 50) + } + + const trigger = () => ( +
+
+ + + + + + + {(url) => ( + + )} + + + + + + +
+
+ ) + + return + }, +}) + +ToolRegistry.register({ + name: "bash", + render(props) { + const i18n = useI18n() + const pending = () => busy(props.status) + const reveal = useToolReveal(pending, () => props.reveal !== false) + const subtitle = () => props.input.description ?? props.metadata.description + + // also apply processCarriageReturns for Windows CLI tools + const cmd = createMemo(() => { + const value = props.input.command ?? props.metadata.command + if (typeof value === "string") return value + return "" + }) + const rawOutput = createMemo(() => { + if (typeof props.output === "string") return props.output + if (typeof props.metadata.output === "string") return props.metadata.output + return "" + }) + const out = createMemo(() => processCarriageReturns(stripAnsi(rawOutput()))) + const text = createMemo(() => `$ ${cmd()}${out() ? "\n\n" + out() : ""}`) + + const hasOutput = createMemo(() => out().length > 0) + const [copied, setCopied] = createSignal(false) + + const handleCopy = async () => { + const command = cmd() + if (!command) return + const content = out() ? `${command}\n\n${out()}` : command + await navigator.clipboard.writeText(content) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + return ( + +
+ + + + {(text) => } +
+
+ } + > +
+
+ + e.preventDefault()} + onClick={handleCopy} + aria-label={copied() ? i18n.t("ui.message.copied") : i18n.t("ui.message.copy")} + /> + +
+
+
+              {text()}
+            
+
+
+ + ) + }, +}) + +ToolRegistry.register({ + name: "edit", + render(props) { + const data = useData() + const i18n = useI18n() + const fileComponent = useFileComponent() + const diagnostics = createMemo(() => getDiagnostics(props.metadata.diagnostics, props.input.filePath)) + const path = createMemo(() => props.metadata?.filediff?.file || props.input.filePath || "") + const filename = () => getFilename(props.input.filePath ?? "") + const pending = () => busy(props.status) + const reveal = useToolReveal(pending, () => props.reveal !== false) + + const handleFileClick = (e: MouseEvent) => { + if (!data.openFile || !props.input.filePath) return + e.stopPropagation() + data.openFile(props.input.filePath) + } + + return ( +
+ +
+
+ + + + + {(name) => ( + + )} + +
+
+
+ } + > + + + {(diff) => } + + } + > +
+ +
+ +
+ + +
+ ) + }, +}) + +ToolRegistry.register({ + name: "write", + render(props) { + const data = useData() + const i18n = useI18n() + const fileComponent = useFileComponent() + const diagnostics = createMemo(() => getDiagnostics(props.metadata.diagnostics, props.input.filePath)) + const path = createMemo(() => props.input.filePath || "") + const filename = () => getFilename(props.input.filePath ?? "") + const pending = () => busy(props.status) + const reveal = useToolReveal(pending, () => props.reveal !== false) + + const handleFileClick = (e: MouseEvent) => { + if (!data.openFile || !props.input.filePath) return + e.stopPropagation() + data.openFile(props.input.filePath) + } + + return ( +
+ +
+
+ + + + + {(name) => ( + + )} + +
+
+
+ } + > + + +
+ +
+
+
+ + +
+ ) + }, +}) + +interface ApplyPatchFile { + filePath: string + relativePath: string + type: "add" | "update" | "delete" | "move" + diff: string + before: string + after: string + additions: number + deletions: number + movePath?: string +} + +ToolRegistry.register({ + name: "apply_patch", + render(props) { + const data = useData() + const i18n = useI18n() + const fileComponent = useFileComponent() + const files = createMemo(() => (props.metadata.files ?? []) as ApplyPatchFile[]) + const pending = createMemo(() => busy(props.status)) + const reveal = useToolReveal(pending, () => props.reveal !== false) + const single = createMemo(() => { + const list = files() + if (list.length !== 1) return + return list[0] + }) + const [expanded, setExpanded] = createSignal([]) + let seeded = false + createEffect(() => { + const list = files() + if (list.length === 0) return + if (seeded) return + seeded = true + setExpanded(list.filter((f) => f.type !== "delete").map((f) => f.filePath)) + }) + const subtitle = createMemo(() => { + const count = files().length + if (count === 0) return "" + return `${count} ${i18n.t(count > 1 ? "ui.common.file.other" : "ui.common.file.one")}` + }) + + return ( +
+ +
+
+ + + + + {(file) => ( + { + e.stopPropagation() + data.openFile!(file().filePath) + } + : undefined + } + /> + )} + + {(text) => } +
+
+
+ } + > + 0}> + setExpanded(Array.isArray(value) ? value : value ? [value] : [])} + > + + {(file) => { + const active = createMemo(() => expanded().includes(file.filePath)) + const [visible, setVisible] = createSignal(false) + createEffect(() => { + if (!active()) { + setVisible(false) + return + } + requestAnimationFrame(() => { + if (!active()) return + setVisible(true) + }) + }) + + return ( + + + +
+
+ +
+ + {`\u202A${getDirectory(file.relativePath)}\u202C`} + + + { + if (!data.openFile) return + e.stopPropagation() + data.openFile(file.filePath) + }} + > + {getFilename(file.relativePath)} + +
+
+
+ + + + {i18n.t("ui.patch.action.created")} + + + + + {i18n.t("ui.patch.action.deleted")} + + + + + {i18n.t("ui.patch.action.moved")} + + + + + + + +
+
+
+
+ + +
+ +
+
+
+
+ ) + }} +
+
+
+ } + > + {(file) => ( + + + + {i18n.t("ui.patch.action.created")} + + + + + {i18n.t("ui.patch.action.deleted")} + + + + + {i18n.t("ui.patch.action.moved")} + + + + + + + } + > +
+ +
+
+ )} +
+ +
+ ) + }, +}) + +ToolRegistry.register({ + name: "todowrite", + render(props) { + const i18n = useI18n() + const todos = createMemo(() => { + const meta = props.metadata?.todos + if (Array.isArray(meta)) return meta + + const input = props.input.todos + if (Array.isArray(input)) return input + + return [] + }) + const pending = createMemo(() => busy(props.status)) + + const subtitle = createMemo(() => { + const list = todos() + if (list.length === 0) return "" + return `${list.filter((t: Todo) => t.status === "completed").length}/${list.length}` + }) + + return ( + + } + > + +
+ + {(todo: Todo) => ( + + + {todo.content} + + + )} + +
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "question", + render(props) { + const i18n = useI18n() + const questions = createMemo(() => (props.input.questions ?? []) as QuestionInfo[]) + const answers = createMemo(() => (props.metadata.answers ?? []) as QuestionAnswer[]) + const completed = createMemo(() => answers().length > 0) + const pending = createMemo(() => busy(props.status)) + + const subtitle = createMemo(() => { + const count = questions().length + if (count === 0) return "" + if (completed()) return i18n.t("ui.question.subtitle.answered", { count }) + return `${count} ${i18n.t(count > 1 ? "ui.common.question.other" : "ui.common.question.one")}` + }) + + return ( + + } + > + +
+ + {(q, i) => { + const answer = () => answers()[i()] ?? [] + return ( +
+
{q.question}
+
{answer().join(", ") || i18n.t("ui.question.answer.none")}
+
+ ) + }} +
+
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "skill", + render(props) { + const i18n = useI18n() + const pending = createMemo(() => busy(props.status)) + const name = createMemo(() => { + const value = props.input.name || props.metadata.name + if (typeof value === "string") return value + }) + return ( + + } + animated + /> + ) + }, +}) diff --git a/packages/kilo-ui/src/components/motion.tsx b/packages/kilo-ui/src/components/motion.tsx new file mode 100644 index 00000000000..6cdf01c7314 --- /dev/null +++ b/packages/kilo-ui/src/components/motion.tsx @@ -0,0 +1,77 @@ +import { followValue } from "motion" +import type { MotionValue } from "motion" + +export { animate, springValue } from "motion" +export type { AnimationPlaybackControls } from "motion" + +/** + * Like `springValue` but preserves getters on the config object. + * `springValue` spreads config at creation, snapshotting getter values. + * This passes the config through to `followValue` intact, so getters + * on `visualDuration` etc. fire on every `.set()` call. + */ +export function tunableSpringValue(initial: T, config: SpringConfig): MotionValue { + return followValue(initial, config as any) +} + +let _growDuration = 0.5 +let _collapsibleDuration = 0.3 + +export const GROW_SPRING = { + type: "spring" as const, + get visualDuration() { + return _growDuration + }, + bounce: 0, +} + +export const COLLAPSIBLE_SPRING = { + type: "spring" as const, + get visualDuration() { + return _collapsibleDuration + }, + bounce: 0, +} + +export const setGrowDuration = (v: number) => { + _growDuration = v +} +export const setCollapsibleDuration = (v: number) => { + _collapsibleDuration = v +} +export const getGrowDuration = () => _growDuration +export const getCollapsibleDuration = () => _collapsibleDuration + +export type SpringConfig = { type: "spring"; visualDuration: number; bounce: number } + +export const FAST_SPRING = { + type: "spring" as const, + visualDuration: 0.35, + bounce: 0, +} + +export const GLOW_SPRING = { + type: "spring" as const, + visualDuration: 0.4, + bounce: 0.15, +} + +export const WIPE_MASK = + "linear-gradient(to right, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 45%, rgba(0,0,0,0) 60%, rgba(0,0,0,0) 100%)" + +export const clearMaskStyles = (el: HTMLElement) => { + el.style.maskImage = "" + el.style.webkitMaskImage = "" + el.style.maskSize = "" + el.style.webkitMaskSize = "" + el.style.maskRepeat = "" + el.style.webkitMaskRepeat = "" + el.style.maskPosition = "" + el.style.webkitMaskPosition = "" +} + +export const clearFadeStyles = (el: HTMLElement) => { + el.style.opacity = "" + el.style.filter = "" + el.style.transform = "" +} diff --git a/packages/kilo-ui/src/components/rolling-results.tsx b/packages/kilo-ui/src/components/rolling-results.tsx new file mode 100644 index 00000000000..77ffdb1b349 --- /dev/null +++ b/packages/kilo-ui/src/components/rolling-results.tsx @@ -0,0 +1,325 @@ +import { For, Show, batch, createEffect, createMemo, createSignal, on, onCleanup, onMount, type JSX } from "solid-js" +import { useReducedMotion } from "../hooks/use-reduced-motion" +import { animate, clearMaskStyles, GROW_SPRING, type AnimationPlaybackControls, type SpringConfig } from "./motion" + +export type RollingResultsProps = { + items: T[] + render: (item: T, index: number) => JSX.Element + fixed?: JSX.Element + getKey?: (item: T, index: number) => string + rows?: number + rowHeight?: number + fixedHeight?: number + rowGap?: number + open?: boolean + scrollable?: boolean + spring?: SpringConfig + animate?: boolean + class?: string + empty?: JSX.Element + noFadeOnCollapse?: boolean +} + +export function RollingResults(props: RollingResultsProps) { + let view: HTMLDivElement | undefined + let track: HTMLDivElement | undefined + let windowEl: HTMLDivElement | undefined + let shift: AnimationPlaybackControls | undefined + let resize: AnimationPlaybackControls | undefined + let edgeFade: AnimationPlaybackControls | undefined + const reduce = useReducedMotion() + + const rows = createMemo(() => Math.max(1, Math.round(props.rows ?? 3))) + const rowHeight = createMemo(() => Math.max(16, Math.round(props.rowHeight ?? 22))) + const fixedHeight = createMemo(() => Math.max(0, Math.round(props.fixedHeight ?? rowHeight()))) + const rowGap = createMemo(() => Math.max(0, Math.round(props.rowGap ?? 0))) + const fixed = createMemo(() => props.fixed !== undefined) + const list = createMemo(() => props.items ?? []) + const count = createMemo(() => list().length) + + // scrollReady is the internal "transition complete" state. + // It only becomes true after props.scrollable is true AND the offset animation has settled. + const [scrollReady, setScrollReady] = createSignal(false) + + const backstop = createMemo(() => Math.max(rows() * 2, 12)) + const rendered = createMemo(() => { + const items = list() + if (scrollReady()) return items + const max = backstop() + return items.length > max ? items.slice(-max) : items + }) + const skipped = createMemo(() => { + if (scrollReady()) return 0 + return count() - rendered().length + }) + const open = createMemo(() => props.open !== false) + const active = createMemo(() => (props.animate !== false || props.spring !== undefined) && !reduce()) + const noFade = () => props.noFadeOnCollapse === true + const overflowing = createMemo(() => count() > rows()) + const shown = createMemo(() => Math.min(rows(), count())) + const step = createMemo(() => rowHeight() + rowGap()) + const offset = createMemo(() => Math.max(0, count() - shown()) * step()) + const body = createMemo(() => { + if (shown() > 0) { + return shown() * rowHeight() + Math.max(0, shown() - 1) * rowGap() + } + if (props.empty === undefined) return 0 + return rowHeight() + }) + const gap = createMemo(() => { + if (!fixed()) return 0 + if (body() <= 0) return 0 + return rowGap() + }) + const height = createMemo(() => { + if (!open()) return 0 + if (!fixed()) return body() + return fixedHeight() + gap() + body() + }) + + const key = (item: T, index: number) => { + const value = props.getKey + if (value) return value(item, index) + return String(index) + } + + const setTrack = (value: number) => { + if (!track) return + track.style.transform = `translateY(${-Math.round(value)}px)` + } + + const setView = (value: number) => { + if (!view) return + view.style.height = `${Math.max(0, Math.round(value))}px` + } + + onMount(() => { + setTrack(offset()) + }) + + // Original WAAPI offset animation — untouched rolling behavior. + createEffect( + on( + offset, + (next) => { + if (!track) return + if (scrollReady()) return + if (props.scrollable) return + if (!active()) { + shift?.stop() + shift = undefined + setTrack(next) + return + } + shift?.stop() + const anim = animate(track, { transform: `translateY(${-next}px)` }, props.spring ?? GROW_SPRING) + shift = anim + anim.finished + .catch(() => {}) + .finally(() => { + if (shift !== anim) return + setTrack(next) + shift = undefined + }) + }, + { defer: true }, + ), + ) + + // Scrollable transition: wait for the offset animation to finish, + // then batch all DOM changes in one synchronous pass. + createEffect( + on( + () => props.scrollable === true, + (isScrollable) => { + if (!isScrollable) { + setScrollReady(false) + if (windowEl) { + windowEl.style.overflowY = "" + windowEl.style.maskImage = "" + windowEl.style.webkitMaskImage = "" + } + return + } + // Wait for the current offset animation to settle (if any). + const done = shift?.finished ?? Promise.resolve() + done + .catch(() => {}) + .then(() => { + if (props.scrollable !== true) return + + // Batch the signal update — Solid updates the DOM synchronously: + // rendered() returns all items, skipped() returns 0, padding-top removed, + // data-scrollable becomes "true". + batch(() => setScrollReady(true)) + + // Now the DOM has all items. Safe to switch layout strategy. + // CSS handles `transform: none !important` on [data-scrollable="true"]. + if (windowEl) { + windowEl.style.overflowY = "auto" + windowEl.scrollTop = windowEl.scrollHeight + } + updateScrollMask() + }) + }, + ), + ) + + // Auto-scroll to bottom when new items arrive in scrollable mode + const [userScrolled, setUserScrolled] = createSignal(false) + + const updateScrollMask = () => { + if (!windowEl) return + if (!scrollReady()) { + windowEl.style.maskImage = "" + windowEl.style.webkitMaskImage = "" + return + } + const { scrollTop, scrollHeight, clientHeight } = windowEl + const atBottom = scrollHeight - scrollTop - clientHeight < 8 + // Top fade is always present in scrollable mode (matches rolling mode appearance). + // Bottom fade only when not scrolled to the end. + const mask = atBottom + ? "linear-gradient(to bottom, transparent 0, black 8px)" + : "linear-gradient(to bottom, transparent 0, black 8px, black calc(100% - 8px), transparent 100%)" + windowEl.style.maskImage = mask + windowEl.style.webkitMaskImage = mask + } + + createEffect(() => { + if (!scrollReady()) { + setUserScrolled(false) + return + } + const _n = count() + const scrolled = userScrolled() + if (scrolled) return + if (windowEl) { + windowEl.scrollTop = windowEl.scrollHeight + updateScrollMask() + } + }) + + const onWindowScroll = () => { + if (!windowEl || !scrollReady()) return + const atBottom = windowEl.scrollHeight - windowEl.scrollTop - windowEl.clientHeight < 8 + setUserScrolled(!atBottom) + updateScrollMask() + } + + const EDGE_MASK = "linear-gradient(to top, transparent 0%, black 8px)" + const applyEdge = () => { + if (!view) return + edgeFade?.stop() + edgeFade = undefined + view.style.maskImage = EDGE_MASK + view.style.webkitMaskImage = EDGE_MASK + view.style.maskSize = "100% 100%" + view.style.maskRepeat = "no-repeat" + } + const clearEdge = () => { + if (!view) return + if (!active()) { + clearMaskStyles(view) + return + } + edgeFade?.stop() + const anim = animate(view, { maskSize: "100% 200%" }, props.spring ?? GROW_SPRING) + edgeFade = anim + anim.finished + .catch(() => {}) + .then(() => { + if (edgeFade !== anim || !view) return + clearMaskStyles(view) + edgeFade = undefined + }) + } + + createEffect( + on(height, (next, prev) => { + if (!view) return + if (!active()) { + resize?.stop() + resize = undefined + setView(next) + view.style.opacity = "" + clearEdge() + return + } + const collapsing = next === 0 && prev !== undefined && prev > 0 + const expanding = prev === 0 && next > 0 + resize?.stop() + view.style.opacity = "" + applyEdge() + const spring = props.spring ?? GROW_SPRING + const anim = collapsing + ? animate(view, noFade() ? { height: `${next}px` } : { height: `${next}px`, opacity: 0 }, spring) + : expanding + ? animate(view, noFade() ? { height: `${next}px` } : { height: `${next}px`, opacity: [0, 1] }, spring) + : animate(view, { height: `${next}px` }, spring) + resize = anim + anim.finished + .catch(() => {}) + .finally(() => { + view.style.opacity = "" + if (resize !== anim) return + setView(next) + resize = undefined + clearEdge() + }) + }), + ) + + onCleanup(() => { + shift?.stop() + resize?.stop() + edgeFade?.stop() + shift = undefined + resize = undefined + edgeFade = undefined + }) + + return ( +
+
+ +
{props.fixed}
+
+
+
+ +
{props.empty}
+
+
+ + {(item, index) => ( +
+ {props.render(item, index())} +
+ )} +
+
+
+
+
+
+ ) +} diff --git a/packages/kilo-ui/src/components/shell-rolling-results.tsx b/packages/kilo-ui/src/components/shell-rolling-results.tsx new file mode 100644 index 00000000000..e5310b6ce08 --- /dev/null +++ b/packages/kilo-ui/src/components/shell-rolling-results.tsx @@ -0,0 +1,291 @@ +import { createEffect, createMemo, createSignal, onCleanup, onMount, Show } from "solid-js" +import stripAnsi from "strip-ansi" +import type { ToolPart } from "@kilocode/sdk/v2" +import { useReducedMotion } from "../hooks/use-reduced-motion" +import { useI18n } from "../context/i18n" +import { RollingResults } from "./rolling-results" +import { Icon } from "./icon" +import { IconButton } from "./icon-button" +import { TextShimmer } from "./text-shimmer" +import { Tooltip } from "./tooltip" +import { GROW_SPRING } from "./motion" +import { useSpring } from "./motion-spring" +import { busy, createThrottledValue, updateScrollMask, useCollapsible, useRowWipe, useToolFade } from "./tool-utils" + +function ShellRollingSubtitle(props: { text: string; animate?: boolean }) { + let ref: HTMLSpanElement | undefined + useToolFade(() => ref, { wipe: true, animate: props.animate }) + + return ( + + {props.text} + + ) +} + +function firstLine(text: string) { + return text + .split(/\r\n|\n|\r/g) + .map((item) => item.trim()) + .find((item) => item.length > 0) +} + +function shellRows(output: string) { + const rows: { id: string; text: string }[] = [] + const lines = output + .split(/\r\n|\n|\r/g) + .map((item) => item.trimEnd()) + .filter((item) => item.length > 0) + const start = Math.max(0, lines.length - 80) + for (let i = start; i < lines.length; i++) { + rows.push({ id: `line:${i}`, text: lines[i]! }) + } + + return rows +} + +function ShellRollingCommand(props: { text: string; animate?: boolean }) { + let ref: HTMLSpanElement | undefined + useToolFade(() => ref, { wipe: true, animate: props.animate }) + + return ( +
+ + $ {props.text} + +
+ ) +} + +function ShellExpanded(props: { cmd: string; out: string; open: boolean }) { + const i18n = useI18n() + const rows = 10 + const rowHeight = 22 + const max = rows * rowHeight + + let contentRef: HTMLDivElement | undefined + let bodyRef: HTMLDivElement | undefined + let scrollRef: HTMLDivElement | undefined + let topRef: HTMLDivElement | undefined + const [copied, setCopied] = createSignal(false) + const [cap, setCap] = createSignal(max) + + const updateMask = () => { + if (scrollRef) updateScrollMask(scrollRef) + } + + const resize = () => { + const top = Math.ceil(topRef?.getBoundingClientRect().height ?? 0) + setCap(Math.max(rowHeight * 2, max - top - (props.out ? 1 : 0))) + } + + const measure = () => { + resize() + return Math.ceil(bodyRef?.getBoundingClientRect().height ?? 0) + } + + onMount(() => { + resize() + if (!topRef) return + const obs = new ResizeObserver(resize) + obs.observe(topRef) + onCleanup(() => obs.disconnect()) + }) + + createEffect(() => { + props.cmd + props.out + queueMicrotask(() => { + resize() + updateMask() + }) + }) + + useCollapsible({ + content: () => contentRef, + body: () => bodyRef, + open: () => props.open, + measure, + onOpen: updateMask, + }) + + const handleCopy = async (e: MouseEvent) => { + e.stopPropagation() + const cmd = props.cmd ? `$ ${props.cmd}` : "" + const text = `${cmd}${props.out ? `${cmd ? "\n\n" : ""}${props.out}` : ""}` + if (!text) return + await navigator.clipboard.writeText(text) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + return ( +
+
+
+
+
+ $ + {props.cmd} +
+
+ + e.preventDefault()} + onClick={handleCopy} + aria-label={copied() ? i18n.t("ui.message.copied") : i18n.t("ui.message.copy")} + /> + +
+
+ + <> +
+
+
+                  {props.out}
+                
+
+ + +
+
+
+ ) +} + +export function ShellRollingResults(props: { part: ToolPart; animate?: boolean; defaultOpen?: boolean }) { + const i18n = useI18n() + const reduce = useReducedMotion() + const wiped = new Set() + const [mounted, setMounted] = createSignal(false) + const [open, setOpen] = createSignal(props.defaultOpen ?? true) + onMount(() => setMounted(true)) + const state = createMemo(() => props.part.state as Record) + const pending = createMemo(() => busy(props.part.state.status)) + const expanded = createMemo(() => open() && !pending()) + const previewOpen = createMemo(() => open() && pending()) + const command = createMemo(() => { + const value = state().input?.command ?? state().metadata?.command + if (typeof value === "string") return value + return "" + }) + const subtitle = createMemo(() => { + const value = state().input?.description ?? state().metadata?.description + if (typeof value === "string" && value.trim().length > 0) return value + return firstLine(command()) ?? "" + }) + const output = createMemo(() => { + const value = state().output ?? state().metadata?.output + if (typeof value === "string") return value + return "" + }) + const skip = () => reduce() || props.animate === false + const opacity = useSpring(() => (mounted() ? 1 : 0), GROW_SPRING) + const blur = useSpring(() => (mounted() ? 0 : 2), GROW_SPRING) + const previewOpacity = useSpring(() => (previewOpen() ? 1 : 0), GROW_SPRING) + const previewBlur = useSpring(() => (previewOpen() ? 0 : 2), GROW_SPRING) + const headerHeight = useSpring(() => (mounted() ? 37 : 0), GROW_SPRING) + let headerClipRef: HTMLDivElement | undefined + const handleHeaderClick = () => { + const el = headerClipRef + const viewport = el?.closest(".scroll-view__viewport") as HTMLElement | null + const beforeY = el?.getBoundingClientRect().top ?? 0 + setOpen((prev) => !prev) + if (viewport && el) { + requestAnimationFrame(() => { + const afterY = el.getBoundingClientRect().top + const delta = afterY - beforeY + if (delta !== 0) viewport.scrollTop += delta + }) + } + } + const line = createMemo(() => firstLine(command())) + const fixed = createMemo(() => { + const value = line() + if (!value) return + return + }) + const text = createThrottledValue(() => stripAnsi(output())) + const rows = createMemo(() => shellRows(text())) + + return ( +
+
+
+ + + + {(text) => } + + + + + +
+
+
+ row.id} + render={(row) => { + const [textRef, setTextRef] = createSignal() + useRowWipe({ + id: () => row.id, + text: () => row.text, + ref: textRef, + seen: wiped, + }) + return ( +
+ + {row.text} + +
+ ) + }} + /> +
+ +
+ ) +} diff --git a/packages/kilo-ui/src/components/text-shimmer.tsx b/packages/kilo-ui/src/components/text-shimmer.tsx new file mode 100644 index 00000000000..382d1ec27d6 --- /dev/null +++ b/packages/kilo-ui/src/components/text-shimmer.tsx @@ -0,0 +1 @@ +export * from "@opencode-ai/ui/text-shimmer" diff --git a/packages/kilo-ui/src/components/tool-count-summary.tsx b/packages/kilo-ui/src/components/tool-count-summary.tsx new file mode 100644 index 00000000000..52bc991829c --- /dev/null +++ b/packages/kilo-ui/src/components/tool-count-summary.tsx @@ -0,0 +1 @@ +export * from "@opencode-ai/ui/tool-count-summary" diff --git a/packages/kilo-ui/src/components/tool-status-title.tsx b/packages/kilo-ui/src/components/tool-status-title.tsx new file mode 100644 index 00000000000..6a95b6d54c3 --- /dev/null +++ b/packages/kilo-ui/src/components/tool-status-title.tsx @@ -0,0 +1 @@ +export * from "@opencode-ai/ui/tool-status-title" diff --git a/packages/kilo-ui/src/components/tool-utils.ts b/packages/kilo-ui/src/components/tool-utils.ts new file mode 100644 index 00000000000..57f981811d9 --- /dev/null +++ b/packages/kilo-ui/src/components/tool-utils.ts @@ -0,0 +1,336 @@ +import type { ToolPart } from "@kilocode/sdk/v2" +import { createEffect, createMemo, createSignal, on, onCleanup, onMount } from "solid-js" +import { useReducedMotion } from "../hooks/use-reduced-motion" +import { + animate, + type AnimationPlaybackControls, + clearFadeStyles, + clearMaskStyles, + COLLAPSIBLE_SPRING, + GROW_SPRING, + WIPE_MASK, +} from "./motion" + +export const TEXT_RENDER_THROTTLE_MS = 100 + +export function createThrottledValue(getValue: () => string) { + const [value, setValue] = createSignal(getValue()) + let timeout: ReturnType | undefined + let last = 0 + + createEffect(() => { + const next = getValue() + const now = Date.now() + + const remaining = TEXT_RENDER_THROTTLE_MS - (now - last) + if (remaining <= 0) { + if (timeout) { + clearTimeout(timeout) + timeout = undefined + } + last = now + setValue(next) + return + } + if (timeout) clearTimeout(timeout) + timeout = setTimeout(() => { + last = Date.now() + setValue(next) + timeout = undefined + }, remaining) + }) + + onCleanup(() => { + if (timeout) clearTimeout(timeout) + }) + + return value +} + +export function busy(status: string | undefined) { + return status === "pending" || status === "running" +} + +export function hold(state: () => boolean, wait = 2000) { + const [live, setLive] = createSignal(state()) + let timer: ReturnType | undefined + + createEffect(() => { + if (state()) { + if (timer) clearTimeout(timer) + timer = undefined + setLive(true) + return + } + + if (timer) clearTimeout(timer) + timer = setTimeout(() => { + timer = undefined + setLive(false) + }, wait) + }) + + onCleanup(() => { + if (timer) clearTimeout(timer) + }) + + return live +} + +export function updateScrollMask(el: HTMLElement, fade = 12) { + const { scrollTop, scrollHeight, clientHeight } = el + const overflow = scrollHeight - clientHeight + if (overflow <= 1) { + el.style.maskImage = "" + el.style.webkitMaskImage = "" + return + } + const top = scrollTop > 1 + const bottom = scrollTop < overflow - 1 + const mask = + top && bottom + ? `linear-gradient(to bottom, transparent 0, black ${fade}px, black calc(100% - ${fade}px), transparent 100%)` + : top + ? `linear-gradient(to bottom, transparent 0, black ${fade}px)` + : bottom + ? `linear-gradient(to bottom, black calc(100% - ${fade}px), transparent 100%)` + : "" + el.style.maskImage = mask + el.style.webkitMaskImage = mask +} + +export function useCollapsible(options: { + content: () => HTMLElement | undefined + body: () => HTMLElement | undefined + open: () => boolean + measure?: () => number + onOpen?: () => void +}) { + const reduce = useReducedMotion() + let heightAnim: AnimationPlaybackControls | undefined + let fadeAnim: AnimationPlaybackControls | undefined + let gen = 0 + + createEffect( + on(options.open, (isOpen) => { + const content = options.content() + const body = options.body() + if (!content || !body) return + heightAnim?.stop() + fadeAnim?.stop() + if (reduce()) { + body.style.opacity = "" + body.style.filter = "" + if (isOpen) { + content.style.display = "" + content.style.height = "auto" + options.onOpen?.() + return + } + content.style.height = "0px" + content.style.display = "none" + return + } + const id = ++gen + if (isOpen) { + content.style.display = "" + content.style.height = "0px" + body.style.opacity = "0" + body.style.filter = "blur(2px)" + fadeAnim = animate(body, { opacity: [0, 1], filter: ["blur(2px)", "blur(0px)"] }, COLLAPSIBLE_SPRING) + queueMicrotask(() => { + if (gen !== id) return + const c = options.content() + if (!c) return + const h = options.measure?.() ?? Math.ceil(body.getBoundingClientRect().height) + heightAnim = animate(c, { height: ["0px", `${h}px`] }, COLLAPSIBLE_SPRING) + heightAnim.finished.then( + () => { + if (gen !== id) return + c.style.height = "auto" + options.onOpen?.() + }, + () => {}, + ) + }) + return + } + + const h = content.getBoundingClientRect().height + heightAnim = animate(content, { height: [`${h}px`, "0px"] }, COLLAPSIBLE_SPRING) + fadeAnim = animate(body, { opacity: [1, 0], filter: ["blur(0px)", "blur(2px)"] }, COLLAPSIBLE_SPRING) + heightAnim.finished.then( + () => { + if (gen !== id) return + content.style.display = "none" + }, + () => {}, + ) + }), + ) + + onCleanup(() => { + ++gen + heightAnim?.stop() + fadeAnim?.stop() + }) +} + +export function useContextToolPending(parts: () => ToolPart[], working?: () => boolean) { + const anyRunning = createMemo(() => parts().some((part) => busy(part.state.status))) + const [settled, setSettled] = createSignal(false) + createEffect(() => { + if (!anyRunning() && !working?.()) setSettled(true) + }) + return createMemo(() => !settled() && (!!working?.() || anyRunning())) +} + +export function useRowWipe(opts: { + id: () => string + text: () => string | undefined + ref: () => HTMLElement | undefined + seen: Set +}) { + const reduce = useReducedMotion() + + createEffect(() => { + const id = opts.id() + const txt = opts.text() + const el = opts.ref() + if (!el) return + if (!txt) { + clearFadeStyles(el) + clearMaskStyles(el) + return + } + if (reduce() || typeof window === "undefined") { + clearFadeStyles(el) + clearMaskStyles(el) + return + } + if (opts.seen.has(id)) { + clearFadeStyles(el) + clearMaskStyles(el) + return + } + opts.seen.add(id) + + el.style.maskImage = WIPE_MASK + el.style.webkitMaskImage = WIPE_MASK + el.style.maskSize = "240% 100%" + el.style.webkitMaskSize = "240% 100%" + el.style.maskRepeat = "no-repeat" + el.style.webkitMaskRepeat = "no-repeat" + el.style.maskPosition = "100% 0%" + el.style.webkitMaskPosition = "100% 0%" + el.style.opacity = "0" + el.style.filter = "blur(2px)" + el.style.transform = "translateX(-0.06em)" + + let done = false + const clear = () => { + if (done) return + done = true + clearFadeStyles(el) + clearMaskStyles(el) + } + if (typeof requestAnimationFrame !== "function") { + clear() + return + } + let anim: AnimationPlaybackControls | undefined + let frame: number | undefined = requestAnimationFrame(() => { + frame = undefined + const node = opts.ref() + if (!node) return + anim = animate( + node, + { + opacity: [0, 1], + filter: ["blur(2px)", "blur(0px)"], + transform: ["translateX(-0.06em)", "translateX(0)"], + maskPosition: "0% 0%", + }, + GROW_SPRING, + ) + + anim.finished.catch(() => {}).finally(clear) + }) + + onCleanup(() => { + if (frame !== undefined) { + cancelAnimationFrame(frame) + clear() + } + }) + }) +} + +export function useToolFade( + ref: () => HTMLElement | undefined, + options?: { delay?: number; wipe?: boolean; animate?: boolean }, +) { + let anim: AnimationPlaybackControls | undefined + let frame: number | undefined + const delay = options?.delay ?? 0 + const wipe = options?.wipe ?? false + const active = options?.animate !== false + const reduce = useReducedMotion() + + onMount(() => { + if (!active) return + + const el = ref() + if (!el || typeof window === "undefined") return + if (reduce()) return + + const mask = + wipe && + typeof CSS !== "undefined" && + (CSS.supports("mask-image", "linear-gradient(to right, black, transparent)") || + CSS.supports("-webkit-mask-image", "linear-gradient(to right, black, transparent)")) + + el.style.opacity = "0" + el.style.filter = wipe ? "blur(3px)" : "blur(2px)" + el.style.transform = wipe ? "translateX(-0.06em)" : "translateY(0.04em)" + + if (mask) { + el.style.maskImage = WIPE_MASK + el.style.webkitMaskImage = WIPE_MASK + el.style.maskSize = "240% 100%" + el.style.webkitMaskSize = "240% 100%" + el.style.maskRepeat = "no-repeat" + el.style.webkitMaskRepeat = "no-repeat" + el.style.maskPosition = "100% 0%" + el.style.webkitMaskPosition = "100% 0%" + } + + frame = requestAnimationFrame(() => { + frame = undefined + const node = ref() + if (!node) return + + anim = wipe + ? mask + ? animate( + node, + { opacity: 1, filter: "blur(0px)", transform: "translateX(0)", maskPosition: "0% 0%" }, + { ...GROW_SPRING, delay }, + ) + : animate(node, { opacity: 1, filter: "blur(0px)", transform: "translateX(0)" }, { ...GROW_SPRING, delay }) + : animate(node, { opacity: 1, filter: "blur(0px)", transform: "translateY(0)" }, { ...GROW_SPRING, delay }) + + anim?.finished.then(() => { + const value = ref() + if (!value) return + clearFadeStyles(value) + if (mask) clearMaskStyles(value) + }) + }) + }) + + onCleanup(() => { + if (frame !== undefined) cancelAnimationFrame(frame) + anim?.stop() + }) +} diff --git a/packages/kilo-ui/src/file-path.ts b/packages/kilo-ui/src/file-path.ts new file mode 100644 index 00000000000..e612dfd75ad --- /dev/null +++ b/packages/kilo-ui/src/file-path.ts @@ -0,0 +1,68 @@ +// Matches text that looks like a file path: +// - Unix: /foo/bar.ts, ./foo.ts, ../foo.ts, foo.ts +// - Windows drive: C:\foo\bar.ts, C:/foo/bar.ts +// - Windows UNC: \\server\share\file.ts +// Supports optional :line or :line:col suffix. +const FILE_PATH_UNIX_RE = + /^((?:\/|\.\.?\/)?(?:[a-zA-Z0-9_@-][a-zA-Z0-9_@./-]*\/)*[a-zA-Z0-9_@.-]+\.[a-zA-Z0-9]+)(?::(\d+)(?::(\d+))?)?$/ +const FILE_PATH_WIN_RE = /^((?:[a-zA-Z]:[/\\]|\\\\)(?:[^\\/]+[/\\])*[^\\/]+\.[a-zA-Z0-9]+)(?::(\d+)(?::(\d+))?)?$/ + +/** + * Parse an inline code span into a file path with optional line/column. + * Returns undefined when the text does not look like a file reference. + * + * Handles Unix paths (`/foo/bar.ts`, `./foo.ts`, `foo.ts`), + * Windows drive paths (`C:\foo\bar.ts`), and UNC paths (`\\server\share\file.ts`). + */ +export function parseFilePath(text: string): { path: string; line?: number; column?: number } | undefined { + if (text.includes("://")) return undefined + if (text.includes(" ")) return undefined + const match = FILE_PATH_UNIX_RE.exec(text) ?? FILE_PATH_WIN_RE.exec(text) + if (!match) return undefined + return { + path: match[1], + line: match[2] ? parseInt(match[2], 10) : undefined, + column: match[3] ? parseInt(match[3], 10) : undefined, + } +} + +const SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:/ + +/** + * Extract a file path from a markdown link href, or return undefined + * when the href is a URL, anchor, scheme, or otherwise not a file reference. + * + * Strips `#fragment` and `?query` suffixes before returning the path. + */ +export function extractFilePathFromHref(href: string): string | undefined { + if (!href) return undefined + // Handle file:// URLs — extract the path component and decode it + if (href.startsWith("file://")) { + try { + const url = new URL(href) + const decoded = decodeURIComponent(url.pathname) + if (!decoded) return undefined + // On Windows, file:///C:/foo gives pathname=/C:/foo — strip the leading slash + // so the result is a valid Windows absolute path (C:/foo). + const c1 = decoded.charCodeAt(1) + const isWindowsDrive = + decoded.length >= 4 && + decoded.charCodeAt(0) === 47 /* / */ && + decoded.charCodeAt(2) === 58 /* : */ && + ((c1 >= 65 && c1 <= 90) /* A-Z */ || (c1 >= 97 && c1 <= 122)) /* a-z */ + return isWindowsDrive ? decoded.slice(1) : decoded + } catch { + return undefined + } + } + // Skip actual URLs and non-file schemes (mailto:, tel:, etc.) + if (href.includes("://") || SCHEME_RE.test(href)) return undefined + // Skip pure anchors + if (href.startsWith("#")) return undefined + // Strip fragment and query before treating as file path + const cleaned = href.replace(/[#?].*$/, "") + if (!cleaned) return undefined + // Must look like a file path (has a dot for extension) + if (!cleaned.includes(".")) return undefined + return cleaned +} diff --git a/packages/kilo-ui/src/hooks/create-auto-scroll.tsx b/packages/kilo-ui/src/hooks/create-auto-scroll.tsx index 3762d8fcfa3..cd490a65f22 100644 --- a/packages/kilo-ui/src/hooks/create-auto-scroll.tsx +++ b/packages/kilo-ui/src/hooks/create-auto-scroll.tsx @@ -1,4 +1,3 @@ -// kilocode_change - new file import { createEffect, on, onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { createResizeObserver } from "@solid-primitives/resize-observer" @@ -8,7 +7,6 @@ const DEBOUNCE_MS = 100 export interface AutoScrollOptions { working: () => boolean onUserInteracted?: () => void - overflowAnchor?: "none" | "auto" | "dynamic" bottomThreshold?: number } @@ -16,10 +14,9 @@ export function createAutoScroll(options: AutoScrollOptions) { let scroll: HTMLElement | undefined let settling = false let settleTimer: ReturnType | undefined - let autoTimer: ReturnType | undefined let stopTimer: ReturnType | undefined let cleanup: (() => void) | undefined - let auto: { time: number } | undefined + let userInitiated = false const threshold = () => options.bottomThreshold ?? 10 @@ -38,36 +35,18 @@ export function createAutoScroll(options: AutoScrollOptions) { return el.scrollHeight - el.clientHeight > 1 } - // Browsers can dispatch scroll events asynchronously. If new content arrives - // between us calling `scrollTo()` and the subsequent `scroll` event firing, - // the handler can see a non-zero `distanceFromBottom` and incorrectly assume - // the user scrolled. - const markAuto = (_el: HTMLElement) => { - auto = { time: Date.now() } - - if (autoTimer) clearTimeout(autoTimer) - autoTimer = setTimeout(() => { - auto = undefined - autoTimer = undefined - }, 250) - } - - const isAuto = (_el: HTMLElement) => { - const a = auto - if (!a) return false - - if (Date.now() - a.time > 250) { - auto = undefined - return false + const markUser = (e: Event) => { + if (e instanceof WheelEvent) { + const target = e.target instanceof Element ? e.target : undefined + const nested = target?.closest("[data-scrollable]") + if (scroll && nested && nested !== scroll) return } - - return true + userInitiated = true } const scrollToBottomNow = (behavior: ScrollBehavior) => { const el = scroll if (!el) return - markAuto(el) if (behavior === "smooth") { el.scrollTo({ top: el.scrollHeight, behavior }) return @@ -122,19 +101,22 @@ export function createAutoScroll(options: AutoScrollOptions) { const el = scroll if (!el) return + const byUser = userInitiated + userInitiated = false + const distance = distanceFromBottom(el) + if (!canScroll(el)) { if (store.userScrolled) setStore("userScrolled", false) return } - if (distanceFromBottom(el) < threshold()) { + if (distance < threshold()) { if (store.userScrolled) setStore("userScrolled", false) return } - // Ignore scroll events triggered by our own scrollToBottom calls. - if (!store.userScrolled && isAuto(el)) { - scrollToBottom(false) + if (!store.userScrolled && !byUser) { + scrollToBottomNow("auto") return } @@ -146,7 +128,6 @@ export function createAutoScroll(options: AutoScrollOptions) { const cur = scroll if (!cur) return if (distanceFromBottom(cur) < threshold()) return - if (!store.userScrolled && isAuto(cur)) return stop() }, DEBOUNCE_MS) } @@ -156,22 +137,6 @@ export function createAutoScroll(options: AutoScrollOptions) { stop() } - const updateOverflowAnchor = (el: HTMLElement) => { - const mode = options.overflowAnchor ?? "dynamic" - - if (mode === "none") { - el.style.overflowAnchor = "none" - return - } - - if (mode === "auto") { - el.style.overflowAnchor = "auto" - return - } - - el.style.overflowAnchor = store.userScrolled ? "auto" : "none" - } - createResizeObserver( () => store.contentRef, () => { @@ -180,8 +145,16 @@ export function createAutoScroll(options: AutoScrollOptions) { if (store.userScrolled) setStore("userScrolled", false) return } - if (!active()) return - if (store.userScrolled) return + if (!active()) { + if (!store.userScrolled && el && distanceFromBottom(el) > threshold()) { + scrollToBottomNow("auto") + return + } + return + } + if (store.userScrolled) { + return + } // ResizeObserver fires after layout, before paint. // Keep the bottom locked in the same frame to avoid visible // "jump up then catch up" artifacts while streaming content. @@ -207,18 +180,8 @@ export function createAutoScroll(options: AutoScrollOptions) { }), ) - createEffect(() => { - // Track `userScrolled` even before `scrollRef` is attached, so we can - // update overflow anchoring once the element exists. - store.userScrolled - const el = scroll - if (!el) return - updateOverflowAnchor(el) - }) - onCleanup(() => { if (settleTimer) clearTimeout(settleTimer) - if (autoTimer) clearTimeout(autoTimer) if (stopTimer) clearTimeout(stopTimer) if (cleanup) cleanup() }) @@ -234,11 +197,19 @@ export function createAutoScroll(options: AutoScrollOptions) { if (!el) return - updateOverflowAnchor(el) + el.style.overflowAnchor = "auto" el.addEventListener("wheel", handleWheel, { passive: true }) + el.addEventListener("wheel", markUser, { passive: true, capture: true }) + el.addEventListener("pointerdown", markUser, { passive: true }) + el.addEventListener("keydown", markUser, { passive: true }) + el.addEventListener("touchstart", markUser, { passive: true }) cleanup = () => { el.removeEventListener("wheel", handleWheel) + el.removeEventListener("wheel", markUser, { capture: true }) + el.removeEventListener("pointerdown", markUser) + el.removeEventListener("keydown", markUser) + el.removeEventListener("touchstart", markUser) } }, contentRef: (el: HTMLElement | undefined) => setStore("contentRef", el), diff --git a/packages/kilo-ui/src/hooks/use-reduced-motion.ts b/packages/kilo-ui/src/hooks/use-reduced-motion.ts new file mode 100644 index 00000000000..0038760ec8e --- /dev/null +++ b/packages/kilo-ui/src/hooks/use-reduced-motion.ts @@ -0,0 +1,10 @@ +import { isHydrated } from "@solid-primitives/lifecycle" +import { createMediaQuery } from "@solid-primitives/media" +import { createHydratableSingletonRoot } from "@solid-primitives/rootless" + +const query = "(prefers-reduced-motion: reduce)" + +export const useReducedMotion = createHydratableSingletonRoot(() => { + const value = createMediaQuery(query) + return () => !isHydrated() || value() +}) diff --git a/packages/kilo-ui/src/i18n/nl.ts b/packages/kilo-ui/src/i18n/nl.ts new file mode 100644 index 00000000000..3ffed965402 --- /dev/null +++ b/packages/kilo-ui/src/i18n/nl.ts @@ -0,0 +1 @@ +export * from "@opencode-ai/ui/i18n/nl" diff --git a/packages/kilo-ui/src/i18n/tr.ts b/packages/kilo-ui/src/i18n/tr.ts new file mode 100644 index 00000000000..1279417d4cf --- /dev/null +++ b/packages/kilo-ui/src/i18n/tr.ts @@ -0,0 +1 @@ +export * from "@opencode-ai/ui/i18n/tr" diff --git a/packages/kilo-ui/src/stories/basic-tool.stories.tsx b/packages/kilo-ui/src/stories/basic-tool.stories.tsx index 5816c932d38..255ea5fe13a 100644 --- a/packages/kilo-ui/src/stories/basic-tool.stories.tsx +++ b/packages/kilo-ui/src/stories/basic-tool.stories.tsx @@ -35,7 +35,7 @@ export const DefaultOpen: Story = { } export const NoChildren: Story = { - render: () => , + render: () => , } export const Locked: Story = { @@ -59,7 +59,7 @@ export const AllVariants: Story = {
All tests passed!
- +
), diff --git a/packages/kilo-ui/src/stories/message-part.stories.tsx b/packages/kilo-ui/src/stories/message-part.stories.tsx index 6278757b755..e67fe32b441 100644 --- a/packages/kilo-ui/src/stories/message-part.stories.tsx +++ b/packages/kilo-ui/src/stories/message-part.stories.tsx @@ -1,8 +1,6 @@ /** @jsxImportSource solid-js */ import type { Meta, StoryObj } from "storybook-solidjs-vite" -import { Message, AssistantMessageDisplay, UserMessageDisplay } from "@opencode-ai/ui/message-part" -// Side-effect import: registers kilo-ui's PART_MAPPING override for reasoning blocks -import "../components/message-part" +import { UserMessageDisplay, AssistantParts } from "../components/message-part" import { DataProvider } from "@opencode-ai/ui/context/data" import { DiffComponentProvider } from "@kilocode/kilo-ui/context/diff" import { CodeComponentProvider } from "@kilocode/kilo-ui/context/code" @@ -59,6 +57,8 @@ const userTextPart: TextPart = { text: "Can you review my code and suggest improvements?", } +// --- Context group tools (read/glob/grep/list) → grouped header path --- + const completedToolPart: ToolPart = { id: "part-tool-001", sessionID: SESSION_ID, @@ -76,17 +76,73 @@ const completedToolPart: ToolPart = { }, } -const runningToolPart: ToolPart = { - id: "part-tool-002", +const grepCompleted: ToolPart = { + id: "part-grep-001", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-grep-001", + tool: "grep", + state: { + status: "completed", + input: { pattern: "createSignal", path: "src/" }, + output: + "src/counter.tsx:1: import { createSignal } from 'solid-js'\nsrc/app.tsx:3: const [count, setCount] = createSignal(0)", + title: "Search", + metadata: {}, + time: { start: now - 7800, end: now - 7400 }, + }, +} + +const globCompleted: ToolPart = { + id: "part-glob-001", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-glob-001", + tool: "glob", + state: { + status: "completed", + input: { pattern: "src/**/*.tsx", path: "." }, + output: "src/counter.tsx\nsrc/app.tsx\nsrc/index.tsx", + title: "Found 3 files", + metadata: {}, + time: { start: now - 7600, end: now - 7300 }, + }, +} + +// --- Bash tool → ShellRollingResults path --- + +const bashCompleted: ToolPart = { + id: "part-bash-001", sessionID: SESSION_ID, messageID: ASST_MSG_ID, type: "tool", callID: "call-bash-001", tool: "bash", state: { - status: "running", + status: "completed", input: { description: "Run tests", command: "bun test" }, - title: "Running tests...", + output: + "bun test v1.0.0\n\n✓ counter.test.tsx > renders correctly (2ms)\n✓ counter.test.tsx > increments count (1ms)\n\n2 tests passed [34ms]", + title: "Run tests", + metadata: {}, + time: { start: now - 5000, end: now - 4500 }, + }, +} + +// --- Edit tool → normal Part/ToolPartDisplay path (non-bash, non-context-group) --- + +const runningToolPart: ToolPart = { + id: "part-tool-002", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-edit-001", + tool: "edit", + state: { + status: "running", + input: { filePath: "src/counter.tsx" }, metadata: {}, time: { start: now - 3000 }, }, @@ -97,17 +153,18 @@ const errorToolPart: ToolPart = { sessionID: SESSION_ID, messageID: ASST_MSG_ID, type: "tool", - callID: "call-bash-002", - tool: "bash", + callID: "call-edit-002", + tool: "edit", state: { status: "error", - input: { description: "Build project", command: "bun build" }, - error: "Build failed: Module not found 'missing-dep'", - metadata: {}, + input: { filePath: "src/missing-file.tsx" }, + error: "ENOENT: no such file or directory 'src/missing-file.tsx'", time: { start: now - 6000, end: now - 5500 }, }, } +// --- Reasoning part --- + const reasoningPart: ReasoningPart = { id: "part-reasoning-001", sessionID: SESSION_ID, @@ -117,22 +174,44 @@ const reasoningPart: ReasoningPart = { time: { start: now - 9000, end: now - 8500 }, } -const mockData = { - session: [], - session_status: {}, - session_diff: {}, - message: { - [SESSION_ID]: [mockUserMessage, mockAssistantMessage], - }, - part: { - [USER_MSG_ID]: [userTextPart], - [ASST_MSG_ID]: [textPart, completedToolPart], - }, +// --------------------------------------------------------------------------- +// Mock data factory — static constants avoid re-creating arrays on every +// reactive access, which would cause SolidJS to see constant "changes". +// --------------------------------------------------------------------------- + +function createMockData(parts: (TextPart | ToolPart | ReasoningPart)[]) { + return { + session: [], + session_status: {}, + session_diff: {}, + message: { + [SESSION_ID]: [mockUserMessage, mockAssistantMessage], + }, + part: { + [USER_MSG_ID]: [userTextPart], + [ASST_MSG_ID]: parts, + }, + } } -function AllProviders(props: { children: any }) { +type MockData = ReturnType + +// AssistantMessage + text + completed read (context group grouped header) +const mockData = createMockData([completedToolPart, textPart]) +// Only the running edit tool — matches old WithRunningTool single-part intent +const mockDataRunning = createMockData([runningToolPart]) +// Only the error edit tool — matches old WithErrorTool single-part intent +const mockDataError = createMockData([errorToolPart]) +// Reasoning + text — matches old WithReasoning single-reasoning intent +const mockDataReasoning = createMockData([reasoningPart, textPart]) +// Completed bash tool — exercises ShellRollingResults path +const mockDataBash = createMockData([bashCompleted]) +// Three context-group tools — exercises ContextToolGroupHeader collapse path +const mockDataContextGroup = createMockData([completedToolPart, grepCompleted, globCompleted, textPart]) + +function AllProviders(props: { children: any; data?: MockData }) { return ( - + @@ -148,6 +227,10 @@ function AllProviders(props: { children: any }) { ) } +// --------------------------------------------------------------------------- +// Stories +// --------------------------------------------------------------------------- + const meta: Meta = { title: "Components/MessagePart", parameters: { layout: "padded" }, @@ -156,6 +239,8 @@ const meta: Meta = { export default meta type Story = StoryObj +// --- User message bubble --- + export const UserMessageStory: Story = { name: "UserMessage", render: () => ( @@ -165,76 +250,194 @@ export const UserMessageStory: Story = { ), } +// --- Assistant: text + one completed read tool (grouped header) --- + export const AssistantMessageStory: Story = { name: "AssistantMessage", render: () => ( - + ), } +// --- Edit tool in running/pending state (Part → ToolPartDisplay path) --- + export const WithRunningTool: Story = { render: () => ( - - + + ), } +// --- Edit tool in error state → renders red error card --- + export const WithErrorTool: Story = { render: () => ( - - + + ), } +// --- User + assistant stacked (tool first, then text — matches original order) --- + export const FullConversationTurn: Story = { render: () => (
- +
), } +// --- Reasoning block collapsed (default state) --- + export const WithReasoningCollapsed: Story = { name: "WithReasoning (collapsed)", render: () => ( - - + + ), } +// --- Reasoning block expanded via play interaction --- + export const WithReasoningExpanded: Story = { name: "WithReasoning (expanded)", - render: () => { - // Use a wrapper to render with the collapsible open by default - const expandedReasoningPart = { ...reasoningPart, id: "part-reasoning-expanded" } - return ( - - - - ) - }, + render: () => ( + + + + ), play: async ({ canvasElement }: { canvasElement: HTMLElement }) => { - // Click the collapsible trigger to expand it const trigger = canvasElement.querySelector("[data-slot='reasoning-header']")?.closest("button") if (trigger) trigger.click() }, } -export const MessageSwitch: Story = { +// --- Bash tool (completed, collapsed) — exercises the ShellRollingResults path --- + +export const WithBashTool: Story = { render: () => ( - -
- - -
+ + + + ), +} + +// --- Bash tool (completed, expanded) — play clicks the header to open the output panel --- + +export const WithBashToolExpanded: Story = { + render: () => ( + + + + ), + play: async ({ canvasElement }: { canvasElement: HTMLElement }) => { + const header = canvasElement.querySelector("[data-slot='shell-rolling-header-clip']") as HTMLElement | null + if (header) header.click() + }, +} + +// --- Three context-group tools + text — exercises ContextToolGroupHeader collapse --- + +export const WithContextGroup: Story = { + render: () => ( + + + + ), +} + +// --- All 5 tool hint error types in a single screenshot --- + +const hintErrors: ToolPart[] = [ + { + id: "part-hint-001", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-hint-001", + tool: "write", + state: { + status: "error", + input: { filePath: "src/config.ts" }, + error: + "Error: File already exists — read it before overwriting it. Use the Read tool first to see its current contents.", + time: { start: now - 6000, end: now - 5500 }, + }, + }, + { + id: "part-hint-002", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-hint-002", + tool: "edit", + state: { + status: "error", + input: { filePath: "src/app.tsx" }, + error: "Error: File has been modified since it was last read. Please read it again before editing.", + time: { start: now - 5500, end: now - 5000 }, + }, + }, + { + id: "part-hint-003", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-hint-003", + tool: "edit", + state: { + status: "error", + input: { filePath: "src/utils.ts" }, + error: "Error: oldString and newString are identical. No changes were made.", + time: { start: now - 5000, end: now - 4500 }, + }, + }, + { + id: "part-hint-004", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-hint-004", + tool: "edit", + state: { + status: "error", + input: { filePath: "src/index.ts" }, + error: + "Error: oldString not found in file. The oldString must match exactly, including whitespace and indentation.", + time: { start: now - 4500, end: now - 4000 }, + }, + }, + { + id: "part-hint-005", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-hint-005", + tool: "edit", + state: { + status: "error", + input: { filePath: "src/counter.tsx" }, + error: + "Error: Found multiple matches for oldString. Provide more surrounding lines to identify the correct match.", + time: { start: now - 4000, end: now - 3500 }, + }, + }, +] + +const mockDataHintErrors = createMockData(hintErrors) + +export const ToolHintErrors: Story = { + render: () => ( + + ), } diff --git a/packages/kilo-ui/src/stories/theme-decorator.tsx b/packages/kilo-ui/src/stories/theme-decorator.tsx index 2153c6cb788..4c95669a14c 100644 --- a/packages/kilo-ui/src/stories/theme-decorator.tsx +++ b/packages/kilo-ui/src/stories/theme-decorator.tsx @@ -41,6 +41,19 @@ export function applyVscodeTheme(vscodeThemeId: string): "light" | "dark" { .map(([k, v]) => ` ${k}: ${v};`) .join("\n") getOrCreateStyle(VSCODE_STYLE_ID).textContent = `:root {\n${vars}\n}` + + // Set VS Code theme body classes (used by HC border selectors) + document.body.classList.remove("vscode-dark", "vscode-light", "vscode-high-contrast", "vscode-high-contrast-light") + if (vscodeThemeId === "hc-black") { + document.body.classList.add("vscode-high-contrast") + } else if (vscodeThemeId === "hc-light") { + document.body.classList.add("vscode-high-contrast", "vscode-high-contrast-light") + } else if (theme.colorScheme === "light") { + document.body.classList.add("vscode-light") + } else { + document.body.classList.add("vscode-dark") + } + return theme.colorScheme } diff --git a/packages/kilo-ui/src/stories/vscode-themes.ts b/packages/kilo-ui/src/stories/vscode-themes.ts index 53fc55189b6..2a2cc4cf70e 100644 --- a/packages/kilo-ui/src/stories/vscode-themes.ts +++ b/packages/kilo-ui/src/stories/vscode-themes.ts @@ -397,6 +397,8 @@ export const VSCODE_THEMES: Record = { "-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, Ubuntu, 'Droid Sans', sans-serif", "--vscode-font-size": "13px", "--vscode-font-weight": "normal", + "--vscode-contrastBorder": "#6FC3DF", + "--vscode-contrastActiveBorder": "#F38518", "--vscode-editor-background": "#000000", "--vscode-editor-foreground": "#FFFFFF", "--vscode-editor-inactiveSelectionBackground": "#3A3D41", @@ -973,6 +975,8 @@ export const VSCODE_THEMES: Record = { "-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, Ubuntu, 'Droid Sans', sans-serif", "--vscode-font-size": "13px", "--vscode-font-weight": "normal", + "--vscode-contrastBorder": "#0F4A85", + "--vscode-contrastActiveBorder": "#0F4A85", "--vscode-editor-background": "#FFFFFF", "--vscode-editor-foreground": "#292929", "--vscode-editor-inactiveSelectionBackground": "#E5EBF1", diff --git a/packages/kilo-ui/src/styles/vscode-bridge.css b/packages/kilo-ui/src/styles/vscode-bridge.css index c6eefffff44..7493ff50c4c 100644 --- a/packages/kilo-ui/src/styles/vscode-bridge.css +++ b/packages/kilo-ui/src/styles/vscode-bridge.css @@ -137,6 +137,10 @@ html[data-theme="kilo-vscode"] { --button-ghost-hover: var(--vscode-toolbar-hoverBackground); --button-ghost-hover2: var(--vscode-toolbar-activeBackground); + /* ===== Contrast (high contrast themes only) ===== */ + --border-contrast: var(--vscode-contrastBorder, transparent); + --border-contrast-active: var(--vscode-contrastActiveBorder, var(--vscode-focusBorder)); + /* ===== Borders ===== */ --border-base: var(--vscode-panel-border, var(--vscode-widget-border)); --border-hover: var(--vscode-panel-border, var(--vscode-widget-border)); diff --git a/packages/kilo-ui/src/theme/default-themes.ts b/packages/kilo-ui/src/theme/default-themes.ts index a048d4e5e4f..d4f3b393809 100644 --- a/packages/kilo-ui/src/theme/default-themes.ts +++ b/packages/kilo-ui/src/theme/default-themes.ts @@ -5,7 +5,7 @@ import kiloVscodeJson from "./themes/kilo-vscode.json" // Re-export all upstream theme constants export { - oc1Theme, + oc2Theme, tokyonightTheme, draculaTheme, monokaiTheme, diff --git a/packages/kilo-ui/src/theme/index.ts b/packages/kilo-ui/src/theme/index.ts index 995377cbe96..d8325b7aabd 100644 --- a/packages/kilo-ui/src/theme/index.ts +++ b/packages/kilo-ui/src/theme/index.ts @@ -36,7 +36,7 @@ export { DEFAULT_THEMES, kiloTheme, kiloVscodeTheme, - oc1Theme, + oc2Theme, tokyonightTheme, draculaTheme, monokaiTheme, @@ -48,4 +48,7 @@ export { shadesOfPurpleTheme, nightowlTheme, vesperTheme, + carbonfoxTheme, + gruvboxTheme, + auraTheme, } from "./default-themes" diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts b/packages/kilo-ui/tests/visual-regression.spec.ts index 24662af93fe..385f1b61809 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts +++ b/packages/kilo-ui/tests/visual-regression.spec.ts @@ -32,6 +32,19 @@ async function fetchStories(): Promise { return Object.values(map).filter((s) => s.id && !s.id.endsWith("--docs")) } +// Animation protection is layered: +// 1. playwright.config.ts `reducedMotion: "reduce"` — emulates the OS +// prefers-reduced-motion media feature before the page loads, so the +// module-level `prefersReducedMotion()` signal (use-reduced-motion.ts) +// initialises to `true`. This disables all JS spring animations driven +// by GrowBox, useSpring, useToolFade, useRowWipe, ShellRollingResults +// and ContextToolRollingResults. +// 2. CSS injection below — zeroes out any remaining CSS animation/transition +// durations (Kobalte collapsible, Tailwind transitions, etc.). +// 3. waitForSettled() — flushes two requestAnimationFrame ticks so that +// SolidJS reactive effects triggered by onMount (e.g. the `mounted()` +// signal one-tick delay in ShellRollingResults) have run and inline +// styles have been updated before the screenshot is taken. async function disableAnimations(page: Page) { await page.addStyleTag({ content: ` @@ -40,11 +53,24 @@ async function disableAnimations(page: Page) { animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; + scroll-behavior: auto !important; } `, }) } +// Flush two animation frames so all SolidJS reactive effects that were +// scheduled during mount (e.g. mounted() signal flips) have been processed +// and written to the DOM before we take a screenshot. +async function waitForSettled(page: Page) { + await page.evaluate( + () => + new Promise((resolve) => { + requestAnimationFrame(() => requestAnimationFrame(() => resolve())) + }), + ) +} + // Wait for every inside the story root to finish loading so screenshots // never capture an intermediate state with missing / half-loaded images. async function waitForImages(page: Page) { @@ -63,6 +89,38 @@ async function waitForImages(page: Page) { }) } +// Wait for all @font-face declarations to resolve so screenshots are never +// taken while fallback fonts (Arial / Courier New) are still active. +async function waitForFonts(page: Page) { + await page.evaluate(() => document.fonts.ready) +} + +// Wait for the DOM inside #storybook-root to be idle for `idle` ms (capped at +// `timeout` ms). This ensures Storybook play() functions and any deferred +// renders (setTimeout, deferredHighlight, etc.) have settled before the screenshot. +async function waitForStable(page: Page, timeout = 2000, idle = 200) { + await page.evaluate( + ({ t, i }: { t: number; i: number }) => + new Promise((resolve) => { + let timer: ReturnType + const root = document.getElementById("storybook-root") + const done = () => { + observer.disconnect() + resolve() + } + const reset = () => { + clearTimeout(timer) + timer = setTimeout(done, i) + } + const observer = new MutationObserver(reset) + if (root) observer.observe(root, { childList: true, subtree: true, attributes: true, characterData: true }) + timer = setTimeout(done, i) + setTimeout(done, t) + }), + { t: timeout, i: idle }, + ) +} + // Stories to skip from visual regression: // - Font/Favicon: inject into , no visible content in #storybook-root // - Typewriter: uses JS setTimeout + Math.random(), inherently non-deterministic @@ -91,6 +149,15 @@ for (const story of stories) { // Wait for Kobalte/SolidJS to finish hydrating interactive components await page.waitForSelector("#storybook-root *", { state: "attached" }) await waitForImages(page) + // Wait for @font-face declarations to resolve (font-display: swap can + // defer swapping to the custom font, causing screenshot diffs). + await waitForFonts(page) + // Flush pending rAF ticks so SolidJS onMount effects (e.g. mounted() + // signal) have updated inline styles before the screenshot is taken. + await waitForSettled(page) + // Wait for the DOM to stop mutating — ensures Storybook play() functions + // and deferred renders (setTimeout, deferredHighlight) have settled. + await waitForStable(page) // Screenshot just the story content, not the full 1280x720 canvas. // Use [component, variant] path so snapshots are grouped per component dir. diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/all-variants-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/all-variants-chromium-linux.png index 20154d22df3..639da753194 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/all-variants-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/all-variants-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dfd2a0c4eb4e848a61d1cc309b637980d71e09325fb330f4329df05e754464d0 -size 9497 +oid sha256:06c58eed6a52681a858a1608c4344a62100f137270ed94b21fa9a756ee6f28f5 +size 10091 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-chromium-linux.png index ee216a48e27..b44905c1442 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ff2fc5b2f48973c4f217292fca770cb8fafafaf084d512d81486243656345b3 -size 2469 +oid sha256:93667a699f6201c9bce26fe19c88baaba28081e5c1f4e61df0250c77cc3b8f73 +size 2468 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-open-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-open-chromium-linux.png index 58e123c1840..aa45b65a810 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-open-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-open-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6213f881a8eaa9a6fde7e4f46fbced82a308afe426433330426469975e9d670e -size 4292 +oid sha256:cf152cf6d1da83922334b7721a3769fc8f0d0e9dfafdb5c25a2db2b8417098db +size 4297 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/generic-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/generic-chromium-linux.png index 4a3a76bcfd1..9175106d1be 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/generic-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/generic-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a9813f847aa72accf4f17d4b3359717274c34189606a0a8cfee203a8e32101c -size 1622 +oid sha256:2691a4b945908a3b352915cde3f306f4eae7a048e1c836260cae82bc1beb77ce +size 2346 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/locked-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/locked-chromium-linux.png index 8f118ea58aa..3c28a03df4d 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/locked-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/locked-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afb54400b855748eac7722a9cef3877fa0b70fd56f466d396a93559d7634767c -size 3637 +oid sha256:a10f017b53c4cad3f896a9536d1abc419100f9324f8bbd3e2aad1831fd371531 +size 3636 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/with-args-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/with-args-chromium-linux.png index 370a29bbb07..5c2ed5046bb 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/with-args-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/with-args-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53f1ef3da39ca34fe50fe48f36a607c83e5b751a471812e1e3eb41d8aaeac5d1 -size 3433 +oid sha256:ff3b75cb03bb60da5c658353263585b4a63cac2b3a26a859226935692fca641e +size 3423 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/collapsed-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/collapsed-chromium-linux.png index dc5d912aa81..8d172ddf2b9 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/collapsed-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/collapsed-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:76e79e29216858903b848fb108d0358af251641748bf9ad55f87ecfb9f5f6429 -size 3103 +oid sha256:361a13d660583e570fff0e6519b5b5d9b0c474e326764fa0cdb4a8556bc9ca33 +size 2961 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/expanded-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/expanded-chromium-linux.png index be157fdb118..bb7609254cc 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/expanded-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/expanded-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79a46aae44755c42c68fcbd25c866547921b1bd494c62ef5796cc9826b288f59 -size 11697 +oid sha256:016c44933c703f4ceecf83161cfc19078d151b7e6cb6da65069ae50158027a5a +size 11196 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/assistant-message-story-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/assistant-message-story-chromium-linux.png index 96459b9b664..7ddf41aa0ad 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/assistant-message-story-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/assistant-message-story-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f36283f93103024b8af2a93e6233cfff6dc8fbc2a5fe273de0f9e709e8f8bc13 -size 15965 +oid sha256:3574bd50a18e91c3ceeb97542f3ad3ff709dfa159a2ce2e3a0cd635418f412d4 +size 14828 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/full-conversation-turn-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/full-conversation-turn-chromium-linux.png index e55234b4c33..27646a659da 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/full-conversation-turn-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/full-conversation-turn-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a993599ddc1f6e3afd5e44f3d4b92d03d6d4e8699128055eeae0089ffabf80f -size 20048 +oid sha256:81fd232992e804e8e0b3453c4e77d358f8c24dd7495b354b8d7de24c7a43724c +size 18986 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/message-switch-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/message-switch-chromium-linux.png deleted file mode 100644 index ce05279a333..00000000000 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/message-switch-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a76639955a7a3e7c5f1369468db6bcbfa07451ebaed080738e3b321f03042490 -size 20048 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/tool-hint-errors-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/tool-hint-errors-chromium-linux.png new file mode 100644 index 00000000000..4650c65cafe --- /dev/null +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/tool-hint-errors-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:958b3b690c8e19c8c4ffc451da476954e9334f5619a1b8b40ce30da848240f6d +size 15354 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/user-message-story-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/user-message-story-chromium-linux.png index 810eebcae2b..c11138b36db 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/user-message-story-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/user-message-story-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8e48fabc63ede1c9ff99614d852ceaeb60b3e53275ff20cd8f03b2dbda79749 -size 3990 +oid sha256:4b690e1cba9e1a7a4eef86162c762092f5908f2d498f0d77f48c44fef1fd44ff +size 4242 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-chromium-linux.png new file mode 100644 index 00000000000..ba0bd944853 --- /dev/null +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6de4487f779501b9d6bf26cc6f2634b7384edba0f47f0c8a22cf8d55cc46d43e +size 13244 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-expanded-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-expanded-chromium-linux.png new file mode 100644 index 00000000000..49a904c94c3 --- /dev/null +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-expanded-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a914f2b8ba47d4b13f0d54d928008edc3e4263d3fa1e4bd6d9c5b5a3641a08b +size 2030 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-context-group-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-context-group-chromium-linux.png new file mode 100644 index 00000000000..84f2ca537a0 --- /dev/null +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-context-group-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b18cb15367b55ea05cc9e13310bf9cf4841584029881abc775a30d1aaba0943 +size 15412 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-error-tool-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-error-tool-chromium-linux.png index 10a1584458d..a2e15f6406c 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-error-tool-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-error-tool-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61695c2c9760589c8f190dba0442de993cc8a362c360c1fa55cc23709979eabb -size 3983 +oid sha256:60821e2616224170657983d1df12ebc5b282efbb2973df8dd8156cdab2e1d20c +size 3729 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-collapsed-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-collapsed-chromium-linux.png index fdf49245b20..ca56f4c8fad 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-collapsed-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-collapsed-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf93ca79d15deab7dc52473f68305b521c62d10e968a9258e09609ad9c04fde6 -size 15837 +oid sha256:6b0f41c54aca88874a3c74151b77ef20f0f17fa9bb2f149c13adfaf4f48de286 +size 14702 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-expanded-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-expanded-chromium-linux.png index 3da58463454..ca56f4c8fad 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-expanded-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-expanded-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14bf991adcbc6fcbf53f4cff2275dcec255943b5545c624231aeb73529ca2d6e -size 32478 +oid sha256:6b0f41c54aca88874a3c74151b77ef20f0f17fa9bb2f149c13adfaf4f48de286 +size 14702 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-running-tool-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-running-tool-chromium-linux.png index 8c8412fcc44..52b6f97307b 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-running-tool-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-running-tool-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96ead064ea9e170ae1323929aeba0734da99f5b1126f869ee6beaa0cd3f1353e -size 2893 +oid sha256:432db47eeb4515a1574068b4ca2f94a0846715b4828a3bc65b6d20b33b703b3d +size 2543 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/default-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/default-chromium-linux.png index 3ec89b92089..5e3dcecb255 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/default-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/default-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1de30d219cd299acf26c9fe473c00f18cf057297db2e9b1ae44fb3116b0392f0 -size 31305 +oid sha256:71a4c5ce0d2bd00ac8428a65e3c4db6c0455720cac5467f8f483a9708cea8765 +size 29370 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/with-steps-expanded-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/with-steps-expanded-chromium-linux.png index 3ec89b92089..5e3dcecb255 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/with-steps-expanded-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/with-steps-expanded-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1de30d219cd299acf26c9fe473c00f18cf057297db2e9b1ae44fb3116b0392f0 -size 31305 +oid sha256:71a4c5ce0d2bd00ac8428a65e3c4db6c0455720cac5467f8f483a9708cea8765 +size 29370 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/working-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/working-chromium-linux.png index f19ccf29edc..6d44ffd8a25 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/working-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/working-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f48b838fb46e05c0b09cd6540e0d4b17b47a40fde82b0c919bceaac01f5446dd -size 6109 +oid sha256:4272e7e538d95ee3c7010dca5711a53643573c0efed2c527d6db58ef23d6c086 +size 4627 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/colored-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/colored-chromium-linux.png index 8e07b31bb12..4dbf5aadcb5 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/colored-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/colored-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfd18d0cb6fe832ac2bcdde94bc7bad523a404ca0afca0646f1fa8189ba07129 -size 988 +oid sha256:ddda0b764400a194989ddb7360b527f67b4d4f9c18c701ab8859974df5454826 +size 826 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/default-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/default-chromium-linux.png index b9eb3865b41..128d5774d58 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/default-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/default-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c58e5334b53a5f19235810a18ae9540566e748e09464947f441dd86e6bf090e3 -size 714 +oid sha256:19797f415357a0c0ab53f73b6d4dff9154c79afc048b48d97e04ea513aa4a3d8 +size 551 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/large-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/large-chromium-linux.png index 3796f95ae69..21257693867 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/large-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/large-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7843a7571c0bda83ecbdcd33918a31abd96f311a3a022b54ec394eb9a52ae910 -size 1418 +oid sha256:eb5c10eb6e92d5cc412eef971397c1136ef715e14e5115e6bb4a8735652ab27c +size 1150 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/small-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/small-chromium-linux.png index e99640be55e..3b626390030 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/small-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/small-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8e730efa18b27ce0bcf6d45f02fe598d19fd1f1292c20bad336e042615dff9c -size 662 +oid sha256:ce16744b389276c3c9dcc1fc1770e711cee5177045a93a932924a468d9b40fb0 +size 519 diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/force-open-chromium-linux.png b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/force-open-chromium-linux.png index 3fb9feec749..877f735e988 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/force-open-chromium-linux.png +++ b/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/force-open-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d59c5c23953d68593619b339170ae2368d53cbcc598334bc9e9ab6856ae4fc28 -size 2122 +oid sha256:6f513acb423e33244a6cc95be1d511fd8d218c817f8faec211a3df31056e9fea +size 2017 diff --git a/packages/kilo-vscode/.storybook/preview.tsx b/packages/kilo-vscode/.storybook/preview.tsx index a662254aebf..21758200fda 100644 --- a/packages/kilo-vscode/.storybook/preview.tsx +++ b/packages/kilo-vscode/.storybook/preview.tsx @@ -71,7 +71,8 @@ const preview: Preview = { { value: "dark-modern", title: "Dark Modern (default)" }, { value: "dark-plus", title: "Dark+" }, { value: "light-modern", title: "Light Modern" }, - { value: "hc-black", title: "High Contrast" }, + { value: "hc-black", title: "High Contrast Dark" }, + { value: "hc-light", title: "High Contrast Light" }, ], dynamicTitle: true, }, diff --git a/packages/kilo-vscode/AGENTS.md b/packages/kilo-vscode/AGENTS.md index 84e24a4544d..ff630a3ac06 100644 --- a/packages/kilo-vscode/AGENTS.md +++ b/packages/kilo-vscode/AGENTS.md @@ -62,6 +62,7 @@ Every client spawns or connects to a `kilo serve` process and communicates via H ## Commands ```bash +bun run extension # Build + launch VS Code with the extension in dev mode bun run compile # Type-check + lint + build bun run watch # Watch mode (esbuild + tsc) bun run test # Run tests (requires pretest compilation) @@ -69,6 +70,8 @@ bun run lint # ESLint on src/ bun run format # Run formatter (do this before committing to avoid styling-only changes in commits) ``` +The `extension` commands also work from the repo root. Pass `--insiders` to prefer VS Code Insiders, `--workspace PATH` to open a different folder, `--clean` to wipe cached state, or `--wait` to block until VS Code closes. VS Code is auto-detected on macOS, Linux, and Windows; override with `--app-path` or `VSCODE_EXEC_PATH`. + Single test: `bun run test -- --grep "test name"` ## CLI Binary @@ -192,16 +195,22 @@ New webview features must use **`@kilocode/kilo-ui`** components instead of raw ## Naming Conventions - All VSCode commands must use `kilo-code.new.` prefix (not `kilo-code.`) -- All view IDs must use `kilo-code.new.` prefix (e.g., `kilo-code.new.sidebarView`) - -## Coexistence with Old Extension - -While the old extension coexists, runtime labels append `(NEW)` — controlled by the flag in [`constants.ts`](src/constants.ts). Static labels in `package.json` must be updated separately. Remove this convention once the old extension is retired. +- All view IDs must use `kilo-code.new.` prefix, **except** the sidebar view which uses `kilo-code.SidebarProvider` to preserve user sidebar position when upgrading from the legacy extension ## Kilocode Change Markers This package is entirely Kilo-specific — `kilocode_change` markers are NOT needed in any files under `packages/kilo-vscode/`. The markers are only necessary when modifying shared upstream opencode files. +## Process Spawning (Windows) + +On Windows, any `spawn`/`execFile`/`exec` call that does not set `windowsHide: true` will flash a cmd.exe console window at the user. To prevent this, **never import `spawn`, `execFile`, or `exec` from `child_process` directly**. Use the wrappers in `src/util/process.ts` instead — they enforce `windowsHide: true` automatically: + +```ts +import { spawn, exec } from "../util/process" +``` + +The `spawn` wrapper covers long-lived processes (e.g. `kilo serve`). The `exec` wrapper covers short commands (e.g. `git`, `tar`). If you need the raw callback form of `execFile` for some reason, pass `windowsHide: true` explicitly in the options object. + ## Style Follow monorepo root AGENTS.md style guide: diff --git a/packages/kilo-vscode/README.md b/packages/kilo-vscode/README.md index 17ee739bb1e..aef1c95a4d2 100644 --- a/packages/kilo-vscode/README.md +++ b/packages/kilo-vscode/README.md @@ -46,6 +46,22 @@ If you want to contribute or modify the extension locally, see the [DEVELOPMENT.md](/DEVELOPMENT.md) file for build and setup instructions. +### Snapshot Builds + +To build and share a development snapshot of the extension: + +```bash +# Run from packages/kilo-vscode/ + +# Build only (outputs VSIX to system temp dir) +bun run snapshot:build + +# Build and install directly into VS Code +bun run snapshot:install +``` + +The snapshot version embeds the current commit SHA and your git username (from `git config user.name`), e.g. `7.0.47-snapshot+8ff7f2d02.kirillk`. + ## Contributing We welcome contributions from developers, writers, and enthusiasts! diff --git a/packages/kilo-vscode/docs/agent-behaviour/mcp-server-creation.md b/packages/kilo-vscode/docs/agent-behaviour/mcp-server-creation.md new file mode 100644 index 00000000000..7656a450dcb --- /dev/null +++ b/packages/kilo-vscode/docs/agent-behaviour/mcp-server-creation.md @@ -0,0 +1,59 @@ +# MCP Servers Sub-Tab Parity + +**Priority:** P2 + +The legacy MCP Servers sub-tab (842 lines) had full server lifecycle management. The new sub-tab can only view and remove servers. + +## Side-by-Side Comparison + +| Feature | Legacy | New | +| ----------------------- | -------------------------------- | ------------------------------------------------------------- | +| View server list | Name + source badge + status dot | Name + command/URL | +| Add server | Via edit config file buttons | Not available | +| Remove server | Delete button + confirmation | Remove button + confirmation | +| Edit server config | Via edit config file buttons | Not available | +| Connection status | Colored dot (green/yellow/red) | Not displayed | +| Enable/disable toggle | `ToggleSwitch` per server | Not available | +| Restart/refresh | Per-server refresh button | Not available | +| Refresh all | "Refresh All MCP Servers" button | Not available | +| Edit Global MCP config | Button to open file | Not available | +| Edit Project MCP config | Button to open file | Not available | +| Network timeout | Per-server dropdown (15s–60min) | Not available | +| Server source badge | Shows "global" / "project" | Not displayed | +| Empty state | N/A | "No MCP servers configured. Edit the opencode config file..." | + +### Expandable Server Detail (Legacy Only) + +When a server was connected and enabled, expanding it showed 5 tabs: + +| Tab | Content | +| ------------ | --------------------------------------------------------------------- | +| Tools | List of MCP tools with tool count | +| Resources | List of resources + resource templates with count | +| Instructions | Server-provided instruction text (if present) | +| Logs | Error/log entries sorted by timestamp with count | +| Auth | OAuth debug info: auth status, token expiration, scopes, refresh info | + +The new extension has none of this expandable detail. + +## Remaining Work + +### Important (P2) + +- **Add MCP Server dialog**: Form to define a new server with name, transport type (stdio/SSE), command+args or URL, environment variables. Write to CLI config via `updateConfig()` +- **Edit MCP Server**: Allow modifying existing server configurations +- **Connection status indicators**: Display per-server connection state. Requires CLI to expose MCP connection status via API or SSE events +- **Enable/disable toggle**: Per-server toggle that writes to CLI config without removing the server +- **Restart/refresh button**: Per-server and "refresh all" buttons. Requires CLI endpoint to restart MCP servers +- **Edit config file buttons**: Quick links to open global/project MCP config in the editor + +### Nice to Have (P3) + +- **Expandable server detail**: Show tools, resources, instructions, and logs per server when expanded. Requires CLI to expose per-server tool/resource/log data +- **Network timeout per server**: If CLI supports per-server timeout config, expose it +- **Server source badge**: Display whether server comes from global or project config +- **OAuth/Auth tab**: Display auth status for OAuth-based MCP servers (depends on CLI support) + +## Notes + +The mcp-and-mcp-hub.md doc in `non-agent-features/` tracks MCP configuration as a broader feature. This doc focuses specifically on the MCP Servers sub-tab within the Agent Behaviour settings tab. The Marketplace covers MCP server discovery and installation from a registry. diff --git a/packages/kilo-vscode/docs/agent-behaviour/modes-subtab-parity.md b/packages/kilo-vscode/docs/agent-behaviour/modes-subtab-parity.md new file mode 100644 index 00000000000..3ce93fff942 --- /dev/null +++ b/packages/kilo-vscode/docs/agent-behaviour/modes-subtab-parity.md @@ -0,0 +1,93 @@ +# Modes / Agents Sub-Tab Parity + +**Priority:** P2 + +The legacy "Modes" sub-tab was a 1794-line component with comprehensive mode management. The new "Agents" sub-tab now covers core CRUD (create, edit, delete) after PR #7225 but is still missing several legacy features. + +## Side-by-Side Comparison + +### Mode/Agent CRUD + +| Feature | Legacy (Modes) | New (Agents) | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| View modes/agents list | List with name + slug | Interactive clickable list with name + description + "custom" badges | +| Select mode to configure | Popover/Command searchable combobox | Click-to-edit in agent list | +| Create new mode | Full dialog: name, slug, save location, role definition, description, when-to-use, tool groups, custom instructions | "Create New Mode" button with form: name (validated), description, system prompt | +| Delete custom mode | Confirmation dialog | Delete button with confirmation dialog | +| Rename custom mode | Inline text field with save/cancel | Not available — name is immutable after creation | +| Export mode | Export to file button | Not available | +| Import mode | Import dialog (project/global) | Not available (marketplace handles this) | +| Edit modes config (JSON) | Dropdown: "Edit Global Modes" / "Edit Project Modes" | Not available | +| Marketplace button | Opens mode marketplace | Not available | + +### Per-Mode/Agent Settings + +| Setting | Legacy | New | +| ------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | +| API Configuration (provider profile) | `