Просмотр исходного кода

Merge branch 'dev' into feature/skill-tool

Mohammad Alhashemi 4 месяцев назад
Родитель
Сommit
cd9eeb7d41
100 измененных файлов с 1736 добавлено и 708 удалено
  1. 70 0
      .github/workflows/docs-update.yml
  2. 10 2
      .github/workflows/publish.yml
  3. 1 0
      STATS.md
  4. 226 132
      bun.lock
  5. 3 3
      flake.lock
  6. 1 1
      nix/hashes.json
  7. 9 1
      package.json
  8. 1 1
      packages/console/app/package.json
  9. 4 4
      packages/console/app/src/config.ts
  10. 1 1
      packages/console/core/package.json
  11. 1 1
      packages/console/function/package.json
  12. 1 1
      packages/console/mail/package.json
  13. 1 1
      packages/desktop/package.json
  14. 11 7
      packages/desktop/src/app.tsx
  15. 19 17
      packages/desktop/src/components/dialog-connect-provider.tsx
  16. 14 7
      packages/desktop/src/components/dialog-manage-models.tsx
  17. 5 6
      packages/desktop/src/components/dialog-select-file.tsx
  18. 11 20
      packages/desktop/src/components/dialog-select-model-unpaid.tsx
  19. 1 2
      packages/desktop/src/components/dialog-select-model.tsx
  20. 2 12
      packages/desktop/src/components/dialog-select-provider.tsx
  21. 35 23
      packages/desktop/src/components/header.tsx
  22. 6 2
      packages/desktop/src/components/prompt-input.tsx
  23. 64 0
      packages/desktop/src/components/session-context-usage.tsx
  24. 0 1
      packages/desktop/src/context/command.tsx
  25. 4 2
      packages/desktop/src/context/layout.tsx
  26. 198 121
      packages/desktop/src/pages/layout.tsx
  27. 167 76
      packages/desktop/src/pages/session.tsx
  28. 1 1
      packages/enterprise/package.json
  29. 23 11
      packages/enterprise/src/routes/share/[shareID].tsx
  30. 6 6
      packages/extensions/zed/extension.toml
  31. 1 1
      packages/function/package.json
  32. 5 3
      packages/opencode/package.json
  33. 1 1
      packages/opencode/script/publish.ts
  34. 10 4
      packages/opencode/src/agent/prompt/summary.txt
  35. 67 34
      packages/opencode/src/cli/cmd/github.ts
  36. 17 0
      packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
  37. 1 1
      packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx
  38. 1 1
      packages/opencode/src/cli/cmd/tui/routes/session/dialog-subagent.tsx
  39. 3 0
      packages/opencode/src/cli/cmd/tui/routes/session/header.tsx
  40. 79 0
      packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
  41. 31 7
      packages/opencode/src/command/template/review.txt
  42. 3 0
      packages/opencode/src/config/config.ts
  43. 1 0
      packages/opencode/src/flag/flag.ts
  44. 7 8
      packages/opencode/src/installation/index.ts
  45. 114 21
      packages/opencode/src/lsp/index.ts
  46. 3 0
      packages/opencode/src/lsp/language.ts
  47. 146 0
      packages/opencode/src/lsp/server.ts
  48. 20 0
      packages/opencode/src/provider/provider.ts
  49. 5 2
      packages/opencode/src/provider/transform.ts
  50. 2 1
      packages/opencode/src/server/server.ts
  51. 14 0
      packages/opencode/src/session/processor.ts
  52. 15 15
      packages/opencode/src/skill/skill.ts
  53. 87 0
      packages/opencode/src/tool/lsp.ts
  54. 19 0
      packages/opencode/src/tool/lsp.txt
  55. 5 3
      packages/opencode/src/tool/read.ts
  56. 2 0
      packages/opencode/src/tool/registry.ts
  57. 26 26
      packages/opencode/test/skill/skill.test.ts
  58. 42 0
      packages/opencode/test/tool/read.test.ts
  59. 1 1
      packages/plugin/package.json
  60. 1 1
      packages/sdk/js/package.json
  61. 8 0
      packages/sdk/js/src/gen/types.gen.ts
  62. 2 0
      packages/sdk/js/src/v2/gen/sdk.gen.ts
  63. 13 0
      packages/sdk/js/src/v2/gen/types.gen.ts
  64. 19 0
      packages/sdk/openapi.json
  65. 1 1
      packages/slack/package.json
  66. 1 1
      packages/tauri/package.json
  67. 4 10
      packages/tauri/scripts/prepare.ts
  68. 5 0
      packages/tauri/scripts/utils.ts
  69. 1 1
      packages/tauri/src-tauri/tauri.conf.json
  70. 1 1
      packages/ui/package.json
  71. 0 1
      packages/ui/src/assets/icons/provider/aihubmix.svg
  72. 2 2
      packages/ui/src/assets/icons/provider/alibaba-cn.svg
  73. 2 2
      packages/ui/src/assets/icons/provider/alibaba.svg
  74. 1 3
      packages/ui/src/assets/icons/provider/amazon-bedrock.svg
  75. 3 7
      packages/ui/src/assets/icons/provider/anthropic.svg
  76. 2 3
      packages/ui/src/assets/icons/provider/azure.svg
  77. 0 1
      packages/ui/src/assets/icons/provider/bailing.svg
  78. 3 1
      packages/ui/src/assets/icons/provider/baseten.svg
  79. 1 2
      packages/ui/src/assets/icons/provider/cerebras.svg
  80. 3 5
      packages/ui/src/assets/icons/provider/cloudflare-ai-gateway.svg
  81. 3 5
      packages/ui/src/assets/icons/provider/cloudflare-workers-ai.svg
  82. 4 18
      packages/ui/src/assets/icons/provider/cohere.svg
  83. 0 1
      packages/ui/src/assets/icons/provider/deepinfra.svg
  84. 0 1
      packages/ui/src/assets/icons/provider/deepseek.svg
  85. 2 2
      packages/ui/src/assets/icons/provider/fastrouter.svg
  86. 2 2
      packages/ui/src/assets/icons/provider/fireworks-ai.svg
  87. 1 4
      packages/ui/src/assets/icons/provider/github-copilot.svg
  88. 3 4
      packages/ui/src/assets/icons/provider/github-models.svg
  89. 4 2
      packages/ui/src/assets/icons/provider/google-vertex.svg
  90. 2 6
      packages/ui/src/assets/icons/provider/google.svg
  91. 2 2
      packages/ui/src/assets/icons/provider/groq.svg
  92. 5 2
      packages/ui/src/assets/icons/provider/helicone.svg
  93. 0 1
      packages/ui/src/assets/icons/provider/huggingface.svg
  94. 0 1
      packages/ui/src/assets/icons/provider/iflowcn.svg
  95. 3 8
      packages/ui/src/assets/icons/provider/inception.svg
  96. 2 2
      packages/ui/src/assets/icons/provider/inference.svg
  97. 4 4
      packages/ui/src/assets/icons/provider/io-net.svg
  98. 0 2
      packages/ui/src/assets/icons/provider/kimi-for-coding.svg
  99. 2 6
      packages/ui/src/assets/icons/provider/llama.svg
  100. 0 2
      packages/ui/src/assets/icons/provider/lucidquery.svg

+ 70 - 0
.github/workflows/docs-update.yml

@@ -0,0 +1,70 @@
+name: Docs Update
+
+on:
+  schedule:
+    # Run every 4 hours
+    - cron: "0 */4 * * *"
+  workflow_dispatch: # Allow manual trigger for testing
+
+jobs:
+  update-docs:
+    if: github.repository == 'sst/opencode'
+    runs-on: blacksmith-4vcpu-ubuntu-2404
+    permissions:
+      id-token: write
+      contents: write
+      pull-requests: write
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0 # Fetch full history to access commits
+
+      - name: Setup Bun
+        uses: ./.github/actions/setup-bun
+
+      - name: Get recent commits
+        id: commits
+        run: |
+          COMMITS=$(git log --since="4 hours ago" --pretty=format:"- %h %s" 2>/dev/null || echo "")
+          if [ -z "$COMMITS" ]; then
+            echo "No commits in the last 4 hours"
+            echo "has_commits=false" >> $GITHUB_OUTPUT
+          else
+            echo "has_commits=true" >> $GITHUB_OUTPUT
+            {
+              echo "list<<EOF"
+              echo "$COMMITS"
+              echo "EOF"
+            } >> $GITHUB_OUTPUT
+          fi
+
+      - name: Run opencode
+        if: steps.commits.outputs.has_commits == 'true'
+        uses: sst/opencode/github@latest
+        env:
+          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
+        with:
+          model: opencode/gpt-5.2
+          agent: docs
+          prompt: |
+            Review the following commits from the last 4 hours and identify any new features that may need documentation.
+
+            <recent_commits>
+            ${{ steps.commits.outputs.list }}
+            </recent_commits>
+
+            Steps:
+            1. For each commit that looks like a new feature or significant change:
+               - Read the changed files to understand what was added
+               - Check if the feature is already documented in packages/web/src/content/docs/*
+            2. If you find undocumented features:
+               - Update the relevant documentation files in packages/web/src/content/docs/*
+               - Follow the existing documentation style and structure
+               - Make sure to document the feature clearly with examples where appropriate
+            3. If all new features are already documented, report that no updates are needed
+            4. If you are creating a new documentation file be sure to update packages/web/astro.config.mjs too.
+
+            Focus on user-facing features and API changes. Skip internal refactors, bug fixes, and test updates unless they affect user-facing behavior.
+            Don't feel the need to document every little thing. It is perfectly okay to make 0 changes at all.
+            Try to keep documentation only for large features or changes that already have a good spot to be documented.

+ 10 - 2
.github/workflows/publish.yml

@@ -79,6 +79,12 @@ jobs:
           AUR_KEY: ${{ secrets.AUR_KEY }}
           GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
           NPM_CONFIG_PROVENANCE: false
+
+      - uses: actions/upload-artifact@v4
+        with:
+          name: opencode-cli
+          path: packages/opencode/dist
+
     outputs:
       release: ${{ steps.publish.outputs.release }}
       tag: ${{ steps.publish.outputs.tag }}
@@ -99,6 +105,8 @@ jobs:
             target: x86_64-pc-windows-msvc
           - host: blacksmith-4vcpu-ubuntu-2404
             target: x86_64-unknown-linux-gnu
+          - host: blacksmith-4vcpu-ubuntu-2404-arm
+            target: aarch64-unknown-linux-gnu
     runs-on: ${{ matrix.settings.host }}
     steps:
       - uses: actions/checkout@v3
@@ -147,7 +155,6 @@ jobs:
           shared-key: ${{ matrix.settings.target }}
 
       - name: Prepare
-        if: inputs.bump || inputs.version
         run: |
           cd packages/tauri
           bun ./scripts/prepare.ts
@@ -159,6 +166,7 @@ jobs:
           OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
           RUST_TARGET: ${{ matrix.settings.target }}
           GH_TOKEN: ${{ github.token }}
+          GITHUB_RUN_ID: ${{ github.run_id }}
 
       # Fixes AppImage build issues, can be removed when https://github.com/tauri-apps/tauri/pull/12491 is released
       - name: Install tauri-cli from portable appimage branch
@@ -186,7 +194,7 @@ jobs:
           projectPath: packages/tauri
           uploadWorkflowArtifacts: true
           tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
-          args: --target ${{ matrix.settings.target }} --config src-tauri/tauri.prod.conf.json
+          args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose
           updaterJsonPreferNsis: true
           releaseId: ${{ needs.publish.outputs.release }}
           tagName: ${{ needs.publish.outputs.tag }}

+ 1 - 0
STATS.md

@@ -177,3 +177,4 @@
 | 2025-12-19 | 1,203,485 (+24,827) | 1,129,698 (+16,280) | 2,333,183 (+41,107) |
 | 2025-12-20 | 1,223,000 (+19,515) | 1,146,258 (+16,560) | 2,369,258 (+36,075) |
 | 2025-12-21 | 1,242,675 (+19,675) | 1,158,909 (+12,651) | 2,401,584 (+32,326) |
+| 2025-12-22 | 1,262,522 (+19,847) | 1,169,121 (+10,212) | 2,431,643 (+30,059) |

+ 226 - 132
bun.lock

@@ -5,6 +5,13 @@
     "": {
       "name": "opencode",
       "dependencies": {
+        "@ai-sdk/cerebras": "1.0.33",
+        "@ai-sdk/cohere": "2.0.21",
+        "@ai-sdk/deepinfra": "1.0.30",
+        "@ai-sdk/gateway": "2.0.23",
+        "@ai-sdk/groq": "2.0.33",
+        "@ai-sdk/perplexity": "2.0.22",
+        "@ai-sdk/togetherai": "1.0.30",
         "@aws-sdk/client-s3": "3.933.0",
         "@opencode-ai/plugin": "workspace:*",
         "@opencode-ai/script": "workspace:*",
@@ -12,6 +19,7 @@
         "typescript": "catalog:",
       },
       "devDependencies": {
+        "@actions/artifact": "5.0.1",
         "@tsconfig/bun": "catalog:",
         "husky": "9.1.7",
         "prettier": "3.6.2",
@@ -21,7 +29,7 @@
     },
     "packages/console/app": {
       "name": "@opencode-ai/console-app",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@cloudflare/vite-plugin": "1.15.2",
         "@ibm/plex": "6.4.1",
@@ -49,7 +57,7 @@
     },
     "packages/console/core": {
       "name": "@opencode-ai/console-core",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@aws-sdk/client-sts": "3.782.0",
         "@jsx-email/render": "1.1.1",
@@ -76,7 +84,7 @@
     },
     "packages/console/function": {
       "name": "@opencode-ai/console-function",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@ai-sdk/anthropic": "2.0.0",
         "@ai-sdk/openai": "2.0.2",
@@ -100,7 +108,7 @@
     },
     "packages/console/mail": {
       "name": "@opencode-ai/console-mail",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@jsx-email/all": "2.2.3",
         "@jsx-email/cli": "1.4.3",
@@ -124,7 +132,7 @@
     },
     "packages/desktop": {
       "name": "@opencode-ai/desktop",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@kobalte/core": "catalog:",
         "@opencode-ai/sdk": "workspace:*",
@@ -172,7 +180,7 @@
     },
     "packages/enterprise": {
       "name": "@opencode-ai/enterprise",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@opencode-ai/ui": "workspace:*",
         "@opencode-ai/util": "workspace:*",
@@ -201,7 +209,7 @@
     },
     "packages/function": {
       "name": "@opencode-ai/function",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@octokit/auth-app": "8.0.1",
         "@octokit/rest": "catalog:",
@@ -217,7 +225,7 @@
     },
     "packages/opencode": {
       "name": "opencode",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "bin": {
         "opencode": "./bin/opencode",
       },
@@ -231,10 +239,12 @@
         "@ai-sdk/google": "2.0.44",
         "@ai-sdk/google-vertex": "3.0.81",
         "@ai-sdk/mcp": "0.0.8",
+        "@ai-sdk/mistral": "2.0.26",
         "@ai-sdk/openai": "2.0.71",
         "@ai-sdk/openai-compatible": "1.0.27",
         "@ai-sdk/provider": "2.0.0",
         "@ai-sdk/provider-utils": "3.0.18",
+        "@ai-sdk/xai": "2.0.42",
         "@clack/prompts": "1.0.0-alpha.1",
         "@hono/standard-validator": "0.1.5",
         "@hono/zod-validator": "catalog:",
@@ -247,8 +257,8 @@
         "@opencode-ai/sdk": "workspace:*",
         "@opencode-ai/util": "workspace:*",
         "@openrouter/ai-sdk-provider": "1.5.2",
-        "@opentui/core": "0.1.62",
-        "@opentui/solid": "0.1.62",
+        "@opentui/core": "0.1.63",
+        "@opentui/solid": "0.1.63",
         "@parcel/watcher": "2.5.1",
         "@pierre/diffs": "catalog:",
         "@solid-primitives/event-bus": "1.1.2",
@@ -309,7 +319,7 @@
     },
     "packages/plugin": {
       "name": "@opencode-ai/plugin",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@opencode-ai/sdk": "workspace:*",
         "zod": "catalog:",
@@ -329,7 +339,7 @@
     },
     "packages/sdk/js": {
       "name": "@opencode-ai/sdk",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "devDependencies": {
         "@hey-api/openapi-ts": "0.88.1",
         "@tsconfig/node22": "catalog:",
@@ -340,7 +350,7 @@
     },
     "packages/slack": {
       "name": "@opencode-ai/slack",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@opencode-ai/sdk": "workspace:*",
         "@slack/bolt": "^3.17.1",
@@ -353,7 +363,7 @@
     },
     "packages/tauri": {
       "name": "@opencode-ai/tauri",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@opencode-ai/desktop": "workspace:*",
         "@solid-primitives/storage": "catalog:",
@@ -380,7 +390,7 @@
     },
     "packages/ui": {
       "name": "@opencode-ai/ui",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@kobalte/core": "catalog:",
         "@opencode-ai/sdk": "workspace:*",
@@ -415,7 +425,7 @@
     },
     "packages/util": {
       "name": "@opencode-ai/util",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "zod": "catalog:",
       },
@@ -426,7 +436,7 @@
     },
     "packages/web": {
       "name": "@opencode-ai/web",
-      "version": "1.0.185",
+      "version": "1.0.187",
       "dependencies": {
         "@astrojs/cloudflare": "12.6.3",
         "@astrojs/markdown-remark": "6.3.1",
@@ -506,7 +516,7 @@
     "zod": "4.1.8",
   },
   "packages": {
-    "@actions/artifact": ["@actions/artifact@4.0.0", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="],
+    "@actions/artifact": ["@actions/artifact@5.0.1", "", { "dependencies": { "@actions/core": "^2.0.0", "@actions/github": "^6.0.1", "@actions/http-client": "^3.0.0", "@azure/storage-blob": "^12.29.1", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-dHJ5rHduhCKUikKTT9eXeWoUvfKia3IjR1sO/VTAV3DVAL4yMTRnl2iO5mcfiBjySHLwPNezwENAVskKYU5ymw=="],
 
     "@actions/core": ["@actions/[email protected]", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="],
 
@@ -514,7 +524,7 @@
 
     "@actions/github": ["@actions/[email protected]", "", { "dependencies": { "@actions/http-client": "^2.2.0", "@octokit/core": "^5.0.1", "@octokit/plugin-paginate-rest": "^9.2.2", "@octokit/plugin-rest-endpoint-methods": "^10.4.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "undici": "^5.28.5" } }, "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw=="],
 
-    "@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
+    "@actions/http-client": ["@actions/http-client@3.0.0", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.28.5" } }, "sha512-1s3tXAfVMSz9a4ZEBkXXRQD4QhY3+GAsWSbaYpeknPOKEeyRiU3lH+bHiLMZdo2x/fIeQ/hscL1wCkDLVM2DZQ=="],
 
     "@actions/io": ["@actions/[email protected]", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
 
@@ -528,22 +538,38 @@
 
     "@ai-sdk/azure": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai": "2.0.71", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LpAg3Ak/V3WOemBu35Qbx9jfQfApsHNXX9p3bXVsnRu3XXi1QQUt5gMOCIb4znPonz+XnHenIDZMBwdsb1TfRQ=="],
 
-    "@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17", "@vercel/oidc": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W+cB1sOWvPcz9qiIsNtD+HxUrBUva2vWv2K1EFukuImX+HA0uZx3EyyOjhYQ9gtf/teqEG80M6OvJ7xx/VLV2A=="],
+    "@ai-sdk/cerebras": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.29", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2gSSS/7kunIwMdC4td5oWsUAzoLw84ccGpz6wQbxVnrb1iWnrEnKa5tRBduaP6IXpzLWsu8wME3+dQhZy+gT7w=="],
+
+    "@ai-sdk/cohere": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZjaZFvJlc5XOPi3QwTLEFZbHIgTJc6YGvxz+8zIMGVZi/hdynR8/f/C1A9x6mhzmBtAqi/dZ2h11oouAQH5z4g=="],
+
+    "@ai-sdk/deepinfra": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.29", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XK8oRZFApzo6xnS5C+FhWUUkB2itA5Nfon3pU9dJVM0goViq8GwdleZTBRqhu4DE4KJURo5DGWpJr2hfV54cEg=="],
+
+    "@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19", "@vercel/oidc": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-qmX7afPRszUqG5hryHF3UN8ITPIRSGmDW6VYCmByzjoUkgm3MekzSx2hMV1wr0P+llDeuXb378SjqUfpvWJulg=="],
 
     "@ai-sdk/google": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-c5dck36FjqiVoeeMJQLTEmUheoURcGTU/nBT6iJu8/nZiKFT/y8pD85KMDRB7RerRYaaQOtslR2d6/5PditiRw=="],
 
     "@ai-sdk/google-vertex": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.50", "@ai-sdk/google": "2.0.44", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "google-auth-library": "^9.15.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-yrl5Ug0Mqwo9ya45oxczgy2RWgpEA/XQQCSFYP+3NZMQ4yA3Iim1vkOjVCsGaZZ8rjVk395abi1ZMZV0/6rqVA=="],
 
+    "@ai-sdk/groq": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-FWGl7xNr88NBveao3y9EcVWYUt9ABPrwLFY7pIutSNgaTf32vgvyhREobaMrLU4Scr5G/2tlNqOPZ5wkYMaZig=="],
+
     "@ai-sdk/mcp": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17", "pkce-challenge": "^5.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-9y9GuGcZ9/+pMIHfpOCJgZVp+AZMv6TkjX2NVT17SQZvTF2N8LXuCXyoUPyi1PxIxzxl0n463LxxaB2O6olC+Q=="],
 
+    "@ai-sdk/mistral": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-jxDB++4WI1wEx5ONNBI+VbkmYJOYIuS8UQY13/83UGRaiW7oB/WHiH4ETe6KzbKpQPB3XruwTJQjUMsMfKyTXA=="],
+
     "@ai-sdk/openai": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-D4zYz2uR90aooKQvX1XnS00Z7PkbrcY+snUvPfm5bCabTG7bzLrVtD56nJ5bSaZG8lmuOMfXpyiEEArYLyWPpw=="],
 
     "@ai-sdk/openai-compatible": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-luHVcU+yKzwv3ekKgbP3v+elUVxb2Rt+8c6w9qi7g2NYG2/pEL21oIrnaEnc6UtTZLLZX9EFBcpq2N1FQKDIMw=="],
 
+    "@ai-sdk/perplexity": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-zwzcnk08R2J3mZcQPn4Ifl4wYGrvANR7jsBB0hCTUSbb+Rx3ybpikSWiGuXQXxdiRc1I5MWXgj70m+bZaLPvHw=="],
+
     "@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="],
 
     "@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ypv1xXMsgGcNKUP+hglKqtdDuMg68nWHucPPAhIENrbFAI+xCHiqPVN8Zllxyv1TNZwGWUghPxJXU+Mqps0YRQ=="],
 
+    "@ai-sdk/togetherai": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.29", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-9bxQbIXnWSN4bNismrza3NvIo+ui/Y3pj3UN6e9vCszCWFCN45RgISi4oDe10RqmzaJ/X8cfO/Tem+K8MT3wGQ=="],
+
+    "@ai-sdk/xai": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.29", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-wlwO4yRoZ/d+ca29vN8SDzxus7POdnL7GBTyRdSrt6icUF0hooLesauC8qRUC4aLxtqvMEc1YHtJOU7ZnLWbTQ=="],
+
     "@alloc/quick-lru": ["@alloc/[email protected]", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
 
     "@ampproject/remapping": ["@ampproject/[email protected]", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
@@ -650,7 +676,7 @@
 
     "@aws/lambda-invoke-store": ["@aws/[email protected]", "", {}, "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww=="],
 
-    "@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="],
+    "@azure/abort-controller": ["@azure/abort-controller@2.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
 
     "@azure/core-auth": ["@azure/[email protected]", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-util": "^1.13.0", "tslib": "^2.6.2" } }, "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg=="],
 
@@ -666,7 +692,7 @@
 
     "@azure/core-rest-pipeline": ["@azure/[email protected]", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg=="],
 
-    "@azure/core-tracing": ["@azure/core-tracing@1.0.0-preview.13", "", { "dependencies": { "@opentelemetry/api": "^1.0.1", "tslib": "^2.2.0" } }, "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ=="],
+    "@azure/core-tracing": ["@azure/core-tracing@1.3.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="],
 
     "@azure/core-util": ["@azure/[email protected]", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A=="],
 
@@ -1088,11 +1114,11 @@
 
     "@octokit/auth-oauth-user": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/auth-oauth-device": "^8.0.3", "@octokit/oauth-methods": "^6.0.2", "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-qLoPPc6E6GJoz3XeDG/pnDhJpTkODTGG4kY0/Py154i/I003O9NazkrwJwRuzgCalhzyIeWQ+6MDvkUmKXjg/A=="],
 
-    "@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
+    "@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="],
 
-    "@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="],
+    "@octokit/core": ["@octokit/core@5.2.2", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="],
 
-    "@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+    "@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="],
 
     "@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^10.0.4", "@octokit/types": "^15.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw=="],
 
@@ -1104,15 +1130,15 @@
 
     "@octokit/plugin-paginate-rest": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw=="],
 
-    "@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="],
+    "@octokit/plugin-request-log": ["@octokit/plugin-request-log@1.0.4", "", { "peerDependencies": { "@octokit/core": ">=3" } }, "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA=="],
 
     "@octokit/plugin-rest-endpoint-methods": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg=="],
 
     "@octokit/plugin-retry": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^6.0.3", "bottleneck": "^2.15.3" } }, "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ=="],
 
-    "@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+    "@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="],
 
-    "@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+    "@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="],
 
     "@octokit/rest": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="],
 
@@ -1162,21 +1188,21 @@
 
     "@opentelemetry/api": ["@opentelemetry/[email protected]", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
 
-    "@opentui/core": ["@opentui/[email protected]2", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.62", "@opentui/core-darwin-x64": "0.1.62", "@opentui/core-linux-arm64": "0.1.62", "@opentui/core-linux-x64": "0.1.62", "@opentui/core-win32-arm64": "0.1.62", "@opentui/core-win32-x64": "0.1.62", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-T9wsXaS4rFoZF2loaEFqAeuGj5DV3pJzrk18z1um3UfUS2NNH4jyDh5rDdHPb2/YrvO1lU9hd0VoAS/7zUAq/w=="],
+    "@opentui/core": ["@opentui/[email protected]3", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.63", "@opentui/core-darwin-x64": "0.1.63", "@opentui/core-linux-arm64": "0.1.63", "@opentui/core-linux-x64": "0.1.63", "@opentui/core-win32-arm64": "0.1.63", "@opentui/core-win32-x64": "0.1.63", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-m4xZQTNCnHXWUWCnGvacJ3Gts1H2aMwP5V/puAG77SDb51jm4W/QOyqAAdgeSakkb9II+8FfUpApX7sfwRXPUg=="],
 
-    "@opentui/core-darwin-arm64": ["@opentui/[email protected]2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-IohPhCkD/DbZEH4M5ft1/o1pI6Vvw2pdxdyoouW/TO1g21W5G8usaWTSRDXO+16BT115Nfb9/DT69H5pzAc2Eg=="],
+    "@opentui/core-darwin-arm64": ["@opentui/[email protected]3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-jKCThZGiiublKkP/hMtDtl1MLCw5NU0hMNJdEYvz1WLT9bzliWf6Kb7MIDAmk32XlbQW8/RHdp+hGyGDXK62OQ=="],
 
-    "@opentui/core-darwin-x64": ["@opentui/[email protected]2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BqbjQl2sLYrJ1Pq1b3H1I2CFedRiMz0QtZX08IMbyZ5kok+J0A8eQS5tmlbfqoS/VH0de9XiEbuHjG09/nSj1A=="],
+    "@opentui/core-darwin-x64": ["@opentui/[email protected]3", "", { "os": "darwin", "cpu": "x64" }, "sha512-rfNxynHzJpxN9i+SAMnn1NToEc8rYj64BsOxY78JNsm4Gg1Js1uyMaawwh2WbdGknFy4cDXS9QwkUMdMcfnjiw=="],
 
-    "@opentui/core-linux-arm64": ["@opentui/[email protected]2", "", { "os": "linux", "cpu": "arm64" }, "sha512-P5FleF+W8O4uGubqBvV8DB1AK0+fJhJS8HvfmTZQ2DhSSJJH9Af/WXqitD7ILQY9ltlaUP7l38BC5cVdxnWzCQ=="],
+    "@opentui/core-linux-arm64": ["@opentui/[email protected]3", "", { "os": "linux", "cpu": "arm64" }, "sha512-wG9d6mHWWKZGrzxYS4c+BrcEGXBv/MYBUPSyjP/lD0CxT+X3h6CYhI317JkRyMNfh3vI9CpAKGFTOFvrTTHimQ=="],
 
-    "@opentui/core-linux-x64": ["@opentui/[email protected]2", "", { "os": "linux", "cpu": "x64" }, "sha512-l9ab5tgOGcdf8k3NU4TzK/3C8UC0+QuMxgLA/j60BhB1e9bwJleFeYJc+wLIktTUu9QwqCsU4YcuGHL+C2lCzA=="],
+    "@opentui/core-linux-x64": ["@opentui/[email protected]3", "", { "os": "linux", "cpu": "x64" }, "sha512-TKSzFv4BgWW3RB/iZmq5qxTR4/tRaXo8IZNnVR+LFzShbPOqhUi466AByy9SUmCxD8uYjmMDFYfKtkCy0AnAwA=="],
 
-    "@opentui/core-win32-arm64": ["@opentui/[email protected]2", "", { "os": "win32", "cpu": "arm64" }, "sha512-U1zsOpQl3EGhs8BwoehKAwwVONe+XOXRnXTxMhXw8huF0WWXDWOUL5psjBvfSWPm1rLmagxkQsH84jTSWA/vLA=="],
+    "@opentui/core-win32-arm64": ["@opentui/[email protected]3", "", { "os": "win32", "cpu": "arm64" }, "sha512-CBWPyPognERP0Mq4eC1q01Ado2C2WU+BLTgMdhyt+E2P4w8rPhJ2kCt2MNxO66vQUiynspmZkgjQr0II/VjxWA=="],
 
-    "@opentui/core-win32-x64": ["@opentui/[email protected]2", "", { "os": "win32", "cpu": "x64" }, "sha512-JgLZXSaE4q7gUIQb9x6fLWFF3BYlMod2VBhOT1qGBdeveZxsM6ZAno/g+CL9IDUydWfLFadOIBjdYFDVWV2Z2w=="],
+    "@opentui/core-win32-x64": ["@opentui/[email protected]3", "", { "os": "win32", "cpu": "x64" }, "sha512-qEp6h//FrT+TQiiHm87wZWUwqTPTqIy1ZD+8R+VCUK+usoQiOAD2SqrYnM7W8JkCMGn5/TKm/GaKLyx/qlK4VA=="],
 
-    "@opentui/solid": ["@opentui/[email protected]2", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.62", "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-3th4oZROv3cZvcoL+IwNCEMTKLZaT1BBWKVHxH29wUD0/EPxtowLQCibnjKDqqdTuEUuFA/QtSX52WqQEioR8g=="],
+    "@opentui/solid": ["@opentui/[email protected]3", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.63", "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-Gccln4qRucAoaoQEZ4NPAHvGmVYzU/8aKCLG8EPgwCKTcpUzlqYt4357cDHq4cnCNOcXOC06hTz/0pK9r0dqXA=="],
 
     "@oslojs/asn1": ["@oslojs/[email protected]", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
 
@@ -1970,7 +1996,7 @@
 
     "bcp-47-match": ["[email protected]", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="],
 
-    "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
+    "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
 
     "bignumber.js": ["[email protected]", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
 
@@ -2342,7 +2368,7 @@
 
     "eventemitter3": ["[email protected]", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
 
-    "events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="],
+    "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
 
     "events-universal": ["[email protected]", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="],
 
@@ -3880,24 +3906,16 @@
 
     "zwitch": ["[email protected]", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
 
-    "@actions/artifact/@octokit/core": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="],
+    "@actions/artifact/@actions/core": ["@actions/[email protected]", "", { "dependencies": { "@actions/exec": "^2.0.0", "@actions/http-client": "^3.0.0" } }, "sha512-oBfqT3GwkvLlo1fjvhQLQxuwZCGTarTE5OuZ2Wg10hvhBj7LRIlF611WT4aZS6fDhO5ZKlY7lCAZTlpmyaHaeg=="],
 
-    "@actions/artifact/@octokit/plugin-request-log": ["@octokit/[email protected]", "", { "peerDependencies": { "@octokit/core": ">=3" } }, "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA=="],
+    "@actions/core/@actions/http-client": ["@actions/[email protected]", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
 
-    "@actions/artifact/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="],
-
-    "@actions/artifact/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="],
-
-    "@actions/github/@octokit/core": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="],
+    "@actions/github/@actions/http-client": ["@actions/[email protected]", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
 
     "@actions/github/@octokit/plugin-paginate-rest": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ=="],
 
     "@actions/github/@octokit/plugin-rest-endpoint-methods": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg=="],
 
-    "@actions/github/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="],
-
-    "@actions/github/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="],
-
     "@actions/github/undici": ["[email protected]", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
 
     "@actions/http-client/undici": ["[email protected]", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
@@ -3914,16 +3932,40 @@
 
     "@ai-sdk/azure/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw=="],
 
-    "@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw=="],
+    "@ai-sdk/cerebras/@ai-sdk/openai-compatible": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+    "@ai-sdk/cerebras/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
+    "@ai-sdk/cohere/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
+    "@ai-sdk/deepinfra/@ai-sdk/openai-compatible": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+    "@ai-sdk/deepinfra/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
+    "@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
 
     "@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-21PaHfoLmouOXXNINTsZJsMw+wE5oLR2He/1kq/sKokTVKyq7ObGT1LDk6ahwxaz/GoaNaGankMh+EgVcdv2Cw=="],
 
+    "@ai-sdk/groq/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
     "@ai-sdk/mcp/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw=="],
 
+    "@ai-sdk/mistral/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
     "@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="],
 
     "@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="],
 
+    "@ai-sdk/perplexity/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
+    "@ai-sdk/togetherai/@ai-sdk/openai-compatible": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+    "@ai-sdk/togetherai/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
+    "@ai-sdk/xai/@ai-sdk/openai-compatible": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+    "@ai-sdk/xai/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA=="],
+
     "@astrojs/cloudflare/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
 
     "@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/[email protected]", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="],
@@ -3968,40 +4010,16 @@
 
     "@aws-sdk/xml-builder/fast-xml-parser": ["[email protected]", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
 
-    "@azure/core-auth/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
-    "@azure/core-client/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
+    "@azure/core-http/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="],
 
-    "@azure/core-client/@azure/core-tracing": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="],
+    "@azure/core-http/@azure/core-tracing": ["@azure/[email protected]", "", { "dependencies": { "@opentelemetry/api": "^1.0.1", "tslib": "^2.2.0" } }, "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ=="],
 
     "@azure/core-http/uuid": ["[email protected]", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
 
     "@azure/core-http/xml2js": ["[email protected]", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="],
 
-    "@azure/core-http-compat/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
-    "@azure/core-lro/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
-    "@azure/core-rest-pipeline/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
-    "@azure/core-rest-pipeline/@azure/core-tracing": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="],
-
-    "@azure/core-util/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
     "@azure/core-xml/fast-xml-parser": ["[email protected]", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
 
-    "@azure/storage-blob/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
-    "@azure/storage-blob/@azure/core-tracing": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="],
-
-    "@azure/storage-blob/events": ["[email protected]", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
-
-    "@azure/storage-common/@azure/abort-controller": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
-
-    "@azure/storage-common/@azure/core-tracing": ["@azure/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="],
-
-    "@azure/storage-common/events": ["[email protected]", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
-
     "@babel/core/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
 
     "@babel/helper-compilation-targets/lru-cache": ["[email protected]", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
@@ -4074,36 +4092,68 @@
 
     "@modelcontextprotocol/sdk/zod": ["[email protected]", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
 
+    "@octokit/auth-app/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
+    "@octokit/auth-app/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
+    "@octokit/auth-oauth-app/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
     "@octokit/auth-oauth-app/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
 
+    "@octokit/auth-oauth-device/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
     "@octokit/auth-oauth-device/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
 
+    "@octokit/auth-oauth-user/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
     "@octokit/auth-oauth-user/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
 
-    "@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="],
+    "@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
+
+    "@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
 
-    "@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+    "@octokit/core/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
 
-    "@octokit/endpoint/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+    "@octokit/endpoint/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
+
+    "@octokit/endpoint/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
+
+    "@octokit/graphql/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
 
     "@octokit/graphql/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="],
 
+    "@octokit/oauth-methods/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
+    "@octokit/oauth-methods/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
     "@octokit/oauth-methods/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
 
+    "@octokit/plugin-paginate-rest/@octokit/core": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="],
+
     "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="],
 
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="],
+
     "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="],
 
     "@octokit/plugin-retry/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^12.11.0" } }, "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg=="],
 
-    "@octokit/request/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+    "@octokit/request/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
+
+    "@octokit/request/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
 
-    "@octokit/request-error/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+    "@octokit/request-error/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
+
+    "@octokit/rest/@octokit/core": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="],
+
+    "@octokit/rest/@octokit/plugin-request-log": ["@octokit/[email protected]", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="],
 
     "@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/[email protected]", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="],
 
     "@openauthjs/openauth/jose": ["[email protected]", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="],
 
+    "@opencode-ai/tauri/@actions/artifact": ["@actions/[email protected]", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="],
+
     "@opencode-ai/tauri/typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
 
     "@opencode-ai/web/@shikijs/transformers": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="],
@@ -4174,6 +4224,8 @@
 
     "accepts/mime-types": ["[email protected]", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
 
+    "ai/@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17", "@vercel/oidc": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-W+cB1sOWvPcz9qiIsNtD+HxUrBUva2vWv2K1EFukuImX+HA0uZx3EyyOjhYQ9gtf/teqEG80M6OvJ7xx/VLV2A=="],
+
     "ai/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw=="],
 
     "ansi-align/string-width": ["[email protected]", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -4198,6 +4250,8 @@
 
     "astro/zod": ["[email protected]", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
 
+    "aws-sdk/events": ["[email protected]", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="],
+
     "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/[email protected]", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
 
     "babel-plugin-module-resolver/glob": ["[email protected]", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
@@ -4332,8 +4386,6 @@
 
     "readable-stream/buffer": ["[email protected]", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
 
-    "readable-stream/events": ["[email protected]", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
-
     "readdir-glob/minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
 
     "router/path-to-regexp": ["[email protected]", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
@@ -4408,46 +4460,14 @@
 
     "zod-to-ts/zod": ["[email protected]", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
 
-    "@actions/artifact/@octokit/core/@octokit/auth-token": ["@octokit/[email protected]", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="],
-
-    "@actions/artifact/@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
-
-    "@actions/artifact/@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
-
-    "@actions/artifact/@octokit/core/before-after-hook": ["[email protected]", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
-
-    "@actions/artifact/@octokit/core/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
+    "@actions/artifact/@actions/core/@actions/exec": ["@actions/[email protected]", "", { "dependencies": { "@actions/io": "^2.0.0" } }, "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw=="],
 
-    "@actions/artifact/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="],
-
-    "@actions/artifact/@octokit/request/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
-
-    "@actions/artifact/@octokit/request/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
-
-    "@actions/artifact/@octokit/request-error/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
-
-    "@actions/github/@octokit/core/@octokit/auth-token": ["@octokit/[email protected]", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="],
-
-    "@actions/github/@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
-
-    "@actions/github/@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
-
-    "@actions/github/@octokit/core/before-after-hook": ["[email protected]", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
-
-    "@actions/github/@octokit/core/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
+    "@actions/core/@actions/http-client/undici": ["[email protected]", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
 
     "@actions/github/@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
 
     "@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
 
-    "@actions/github/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="],
-
-    "@actions/github/@octokit/request/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
-
-    "@actions/github/@octokit/request/universal-user-agent": ["[email protected]", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
-
-    "@actions/github/@octokit/request-error/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
-
     "@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="],
 
     "@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="],
@@ -4638,29 +4658,93 @@
 
     "@modelcontextprotocol/sdk/raw-body/http-errors": ["[email protected]", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
 
+    "@octokit/auth-app/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/auth-app/@octokit/request/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+
+    "@octokit/auth-app/@octokit/request-error/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+
+    "@octokit/auth-oauth-app/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/auth-oauth-app/@octokit/request/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
     "@octokit/auth-oauth-app/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
 
+    "@octokit/auth-oauth-device/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/auth-oauth-device/@octokit/request/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
     "@octokit/auth-oauth-device/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
 
+    "@octokit/auth-oauth-user/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/auth-oauth-user/@octokit/request/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
     "@octokit/auth-oauth-user/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
 
-    "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+    "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
+
+    "@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
+
+    "@octokit/graphql/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
 
-    "@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+    "@octokit/graphql/@octokit/request/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
+    "@octokit/graphql/@octokit/request/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
 
     "@octokit/graphql/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="],
 
+    "@octokit/oauth-methods/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
     "@octokit/oauth-methods/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
 
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/auth-token": ["@octokit/[email protected]", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/before-after-hook": ["[email protected]", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
+
     "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="],
 
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/auth-token": ["@octokit/[email protected]", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/before-after-hook": ["[email protected]", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
+
     "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="],
 
     "@octokit/plugin-retry/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="],
 
-    "@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+    "@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
+
+    "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
 
-    "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+    "@octokit/rest/@octokit/core/@octokit/auth-token": ["@octokit/[email protected]", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
+
+    "@octokit/rest/@octokit/core/@octokit/graphql": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="],
+
+    "@octokit/rest/@octokit/core/@octokit/request": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="],
+
+    "@octokit/rest/@octokit/core/@octokit/request-error": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
+
+    "@octokit/rest/@octokit/core/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
+
+    "@octokit/rest/@octokit/core/before-after-hook": ["[email protected]", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
+
+    "@opencode-ai/tauri/@actions/artifact/@actions/http-client": ["@actions/[email protected]", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
 
     "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="],
 
@@ -4918,22 +5002,12 @@
 
     "wrap-ansi-cjs/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
 
-    "@actions/artifact/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
-
-    "@actions/artifact/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
-
-    "@actions/artifact/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
-
-    "@actions/github/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
+    "@actions/artifact/@actions/core/@actions/exec/@actions/io": ["@actions/[email protected]", "", {}, "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg=="],
 
     "@actions/github/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
 
     "@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
 
-    "@actions/github/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
-
-    "@actions/github/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
-
     "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="],
 
     "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="],
@@ -5016,6 +5090,26 @@
 
     "@modelcontextprotocol/sdk/raw-body/http-errors/statuses": ["[email protected]", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
 
+    "@octokit/auth-app/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+
+    "@octokit/auth-app/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+
+    "@octokit/graphql/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+
+    "@octokit/rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
+
+    "@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
+
+    "@opencode-ai/tauri/@actions/artifact/@actions/http-client/undici": ["[email protected]", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
+
     "@slack/web-api/form-data/mime-types/mime-db": ["[email protected]", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
 
     "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["[email protected]", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="],

+ 3 - 3
flake.lock

@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1766125104,
-        "narHash": "sha256-l/YGrEpLromL4viUo5GmFH3K5M1j0Mb9O+LiaeCPWEM=",
+        "lastModified": 1766314097,
+        "narHash": "sha256-laJftWbghBehazn/zxVJ8NdENVgjccsWAdAqKXhErrM=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "7d853e518814cca2a657b72eeba67ae20ebf7059",
+        "rev": "306ea70f9eb0fb4e040f8540e2deab32ed7e2055",
         "type": "github"
       },
       "original": {

+ 1 - 1
nix/hashes.json

@@ -1,3 +1,3 @@
 {
-  "nodeModules": "sha256-XhU8gEwLPUtzFhMfg+QxExn5/WiDo5VVOiZ0AmklRwc="
+  "nodeModules": "sha256-SJSVpKmRDS24yzZ3ypYKWVyntOG0TNrrpqQXUkf8gXY="
 }

+ 9 - 1
package.json

@@ -56,6 +56,7 @@
     }
   },
   "devDependencies": {
+    "@actions/artifact": "5.0.1",
     "@tsconfig/bun": "catalog:",
     "husky": "9.1.7",
     "prettier": "3.6.2",
@@ -63,10 +64,17 @@
     "turbo": "2.5.6"
   },
   "dependencies": {
+    "@ai-sdk/cerebras": "1.0.33",
+    "@ai-sdk/cohere": "2.0.21",
+    "@ai-sdk/deepinfra": "1.0.30",
+    "@ai-sdk/gateway": "2.0.23",
+    "@ai-sdk/groq": "2.0.33",
+    "@ai-sdk/perplexity": "2.0.22",
+    "@ai-sdk/togetherai": "1.0.30",
     "@aws-sdk/client-s3": "3.933.0",
+    "@opencode-ai/plugin": "workspace:*",
     "@opencode-ai/script": "workspace:*",
     "@opencode-ai/sdk": "workspace:*",
-    "@opencode-ai/plugin": "workspace:*",
     "typescript": "catalog:"
   },
   "repository": {

+ 1 - 1
packages/console/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/console-app",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "type": "module",
   "scripts": {
     "typecheck": "tsgo --noEmit",

+ 4 - 4
packages/console/app/src/config.ts

@@ -9,8 +9,8 @@ export const config = {
   github: {
     repoUrl: "https://github.com/sst/opencode",
     starsFormatted: {
-      compact: "38K",
-      full: "38,000",
+      compact: "41K",
+      full: "41,000",
     },
   },
 
@@ -22,8 +22,8 @@ export const config = {
 
   // Static stats (used on landing page)
   stats: {
-    contributors: "400",
-    commits: "5,000",
+    contributors: "450",
+    commits: "6,000",
     monthlyUsers: "400,000",
   },
 } as const

+ 1 - 1
packages/console/core/package.json

@@ -1,7 +1,7 @@
 {
   "$schema": "https://json.schemastore.org/package.json",
   "name": "@opencode-ai/console-core",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "private": true,
   "type": "module",
   "dependencies": {

+ 1 - 1
packages/console/function/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/console-function",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "$schema": "https://json.schemastore.org/package.json",
   "private": true,
   "type": "module",

+ 1 - 1
packages/console/mail/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/console-mail",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "dependencies": {
     "@jsx-email/all": "2.2.3",
     "@jsx-email/cli": "1.4.3",

+ 1 - 1
packages/desktop/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/desktop",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "description": "",
   "type": "module",
   "exports": {

+ 11 - 7
packages/desktop/src/app.tsx

@@ -21,6 +21,7 @@ import Home from "@/pages/home"
 import DirectoryLayout from "@/pages/directory-layout"
 import Session from "@/pages/session"
 import { ErrorPage } from "./pages/error"
+import { iife } from "@opencode-ai/util/iife"
 
 declare global {
   interface Window {
@@ -28,14 +29,17 @@ declare global {
   }
 }
 
-const host = import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "127.0.0.1"
-const port = window.__OPENCODE__?.port ?? import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"
+const url = iife(() => {
+  const param = new URLSearchParams(document.location.search).get("url")
+  if (param) return param
 
-const url =
-  new URLSearchParams(document.location.search).get("url") ||
-  (location.hostname.includes("opencode.ai") || location.hostname.includes("localhost")
-    ? `http://${host}:${port}`
-    : "/")
+  if (location.hostname.includes("opencode.ai")) return "http://localhost:4096"
+  if (window.__OPENCODE__) return `http://127.0.0.1:${window.__OPENCODE__.port}`
+  if (import.meta.env.VITE_OPENCODE_SERVER)
+    return `http://${import.meta.env.VITE_OPENCODE_SERVER_HOST}:${import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"}`
+
+  return "/"
+})
 
 export function App() {
   return (

+ 19 - 17
packages/desktop/src/components/dialog-connect-provider.tsx

@@ -1,24 +1,24 @@
-import { createMemo, Match, onCleanup, onMount, Switch } from "solid-js"
-import { createStore, produce } from "solid-js/store"
+import type { ProviderAuthAuthorization } from "@opencode-ai/sdk/v2/client"
+import { Button } from "@opencode-ai/ui/button"
 import { useDialog } from "@opencode-ai/ui/context/dialog"
-import { useGlobalSync } from "@/context/global-sync"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { usePlatform } from "@/context/platform"
-import { ProviderAuthAuthorization } from "@opencode-ai/sdk/v2/client"
 import { Dialog } from "@opencode-ai/ui/dialog"
-import { List, ListRef } from "@opencode-ai/ui/list"
-import { Button } from "@opencode-ai/ui/button"
+import { Icon } from "@opencode-ai/ui/icon"
 import { IconButton } from "@opencode-ai/ui/icon-button"
-import { TextField } from "@opencode-ai/ui/text-field"
+import type { IconName } from "@opencode-ai/ui/icons/provider"
+import { List, type ListRef } from "@opencode-ai/ui/list"
+import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
 import { Spinner } from "@opencode-ai/ui/spinner"
-import { Icon } from "@opencode-ai/ui/icon"
+import { TextField } from "@opencode-ai/ui/text-field"
 import { showToast } from "@opencode-ai/ui/toast"
-import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
-import { IconName } from "@opencode-ai/ui/icons/provider"
 import { iife } from "@opencode-ai/util/iife"
+import { createMemo, Match, onCleanup, onMount, Switch } from "solid-js"
+import { createStore, produce } from "solid-js/store"
 import { Link } from "@/components/link"
-import { DialogSelectProvider } from "./dialog-select-provider"
+import { useGlobalSDK } from "@/context/global-sdk"
+import { useGlobalSync } from "@/context/global-sync"
+import { usePlatform } from "@/context/platform"
 import { DialogSelectModel } from "./dialog-select-model"
+import { DialogSelectProvider } from "./dialog-select-provider"
 
 export function DialogConnectProvider(props: { provider: string }) {
   const dialog = useDialog()
@@ -154,7 +154,9 @@ export function DialogConnectProvider(props: { provider: string }) {
               <div class="text-14-regular text-text-base">Select login method for {provider().name}.</div>
               <div class="">
                 <List
-                  ref={(ref) => (listRef = ref)}
+                  ref={(ref) => {
+                    listRef = ref
+                  }}
                   items={methods}
                   key={(m) => m?.label}
                   onSelect={async (method, index) => {
@@ -163,7 +165,7 @@ export function DialogConnectProvider(props: { provider: string }) {
                   }}
                 >
                   {(i) => (
-                    <div class="w-full flex items-center gap-x-4">
+                    <div class="w-full flex items-center gap-x-2">
                       <div class="w-4 h-2 rounded-[1px] bg-input-base shadow-xs-border-base flex items-center justify-center">
                         <div class="w-2.5 h-0.5 bg-icon-strong-base hidden" data-slot="list-item-extra-icon" />
                       </div>
@@ -175,7 +177,7 @@ export function DialogConnectProvider(props: { provider: string }) {
             </Match>
             <Match when={store.state === "pending"}>
               <div class="text-14-regular text-text-base">
-                <div class="flex items-center gap-x-4">
+                <div class="flex items-center gap-x-2">
                   <Spinner />
                   <span>Authorization in progress...</span>
                 </div>
@@ -183,7 +185,7 @@ export function DialogConnectProvider(props: { provider: string }) {
             </Match>
             <Match when={store.state === "error"}>
               <div class="text-14-regular text-text-base">
-                <div class="flex items-center gap-x-4">
+                <div class="flex items-center gap-x-2">
                   <Icon name="circle-ban-sign" class="text-icon-critical-base" />
                   <span>Authorization failed: {store.error}</span>
                 </div>

+ 14 - 7
packages/desktop/src/components/dialog-manage-models.tsx

@@ -1,16 +1,15 @@
-import { Component } from "solid-js"
-import { useLocal } from "@/context/local"
-import { popularProviders } from "@/hooks/use-providers"
 import { Dialog } from "@opencode-ai/ui/dialog"
 import { List } from "@opencode-ai/ui/list"
 import { Switch } from "@opencode-ai/ui/switch"
+import type { Component } from "solid-js"
+import { useLocal } from "@/context/local"
+import { popularProviders } from "@/hooks/use-providers"
 
 export const DialogManageModels: Component = () => {
   const local = useLocal()
   return (
     <Dialog title="Manage models" description="Customize which models appear in the model selector.">
       <List
-        class="px-2.5"
         search={{ placeholder: "Search models", autofocus: true }}
         emptyMessage="No model results"
         key={(x) => `${x?.provider?.id}:${x?.id}`}
@@ -27,16 +26,24 @@ export const DialogManageModels: Component = () => {
         }}
         onSelect={(x) => {
           if (!x) return
-          const visible = local.model.visible({ modelID: x.id, providerID: x.provider.id })
+          const visible = local.model.visible({
+            modelID: x.id,
+            providerID: x.provider.id,
+          })
           local.model.setVisibility({ modelID: x.id, providerID: x.provider.id }, !visible)
         }}
       >
         {(i) => (
-          <div class="w-full flex items-center justify-between gap-x-2.5">
+          <div class="w-full flex items-center justify-between gap-x-3">
             <span>{i.name}</span>
             <div onClick={(e) => e.stopPropagation()}>
               <Switch
-                checked={!!local.model.visible({ modelID: i.id, providerID: i.provider.id })}
+                checked={
+                  !!local.model.visible({
+                    modelID: i.id,
+                    providerID: i.provider.id,
+                  })
+                }
                 onChange={(checked) => {
                   local.model.setVisibility({ modelID: i.id, providerID: i.provider.id }, checked)
                 }}

+ 5 - 6
packages/desktop/src/components/dialog-select-file.tsx

@@ -1,12 +1,12 @@
-import { useLocal } from "@/context/local"
+import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { Dialog } from "@opencode-ai/ui/dialog"
-import { List } from "@opencode-ai/ui/list"
 import { FileIcon } from "@opencode-ai/ui/file-icon"
+import { List } from "@opencode-ai/ui/list"
 import { getDirectory, getFilename } from "@opencode-ai/util/path"
-import { useLayout } from "@/context/layout"
-import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { useParams } from "@solidjs/router"
 import { createMemo } from "solid-js"
+import { useLayout } from "@/context/layout"
+import { useLocal } from "@/context/local"
 
 export function DialogSelectFile() {
   const layout = useLayout()
@@ -18,7 +18,6 @@ export function DialogSelectFile() {
   return (
     <Dialog title="Select file">
       <List
-        class="px-2.5"
         search={{ placeholder: "Search files", autofocus: true }}
         emptyMessage="No files found"
         items={local.file.searchFiles}
@@ -32,7 +31,7 @@ export function DialogSelectFile() {
       >
         {(i) => (
           <div class="w-full flex items-center justify-between rounded-md">
-            <div class="flex items-center gap-x-2 grow min-w-0">
+            <div class="flex items-center gap-x-3 grow min-w-0">
               <FileIcon node={{ path: i, type: "file" }} class="shrink-0 size-4" />
               <div class="flex items-center text-14-regular">
                 <span class="text-text-weak whitespace-nowrap overflow-hidden overflow-ellipsis truncate min-w-0">

+ 11 - 20
packages/desktop/src/components/dialog-select-model-unpaid.tsx

@@ -1,15 +1,15 @@
-import { Component, onCleanup, onMount, Show } from "solid-js"
-import { useLocal } from "@/context/local"
-import { useDialog } from "@opencode-ai/ui/context/dialog"
-import { popularProviders, useProviders } from "@/hooks/use-providers"
 import { Button } from "@opencode-ai/ui/button"
-import { Tag } from "@opencode-ai/ui/tag"
+import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { Dialog } from "@opencode-ai/ui/dialog"
-import { List, ListRef } from "@opencode-ai/ui/list"
+import type { IconName } from "@opencode-ai/ui/icons/provider"
+import { List, type ListRef } from "@opencode-ai/ui/list"
 import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
-import { IconName } from "@opencode-ai/ui/icons/provider"
-import { DialogSelectProvider } from "./dialog-select-provider"
+import { Tag } from "@opencode-ai/ui/tag"
+import { type Component, onCleanup, onMount, Show } from "solid-js"
+import { useLocal } from "@/context/local"
+import { popularProviders, useProviders } from "@/hooks/use-providers"
 import { DialogConnectProvider } from "./dialog-connect-provider"
+import { DialogSelectProvider } from "./dialog-select-provider"
 
 export const DialogSelectModelUnpaid: Component = () => {
   const local = useLocal()
@@ -64,7 +64,7 @@ export const DialogSelectModelUnpaid: Component = () => {
             <div class="px-2 text-14-medium text-text-base">Add more models from popular providers</div>
             <div class="w-full">
               <List
-                class="w-full"
+                class="w-full px-0"
                 key={(x) => x?.id}
                 items={providers.popular}
                 activeIcon="plus-small"
@@ -79,17 +79,8 @@ export const DialogSelectModelUnpaid: Component = () => {
                 }}
               >
                 {(i) => (
-                  <div class="w-full flex items-center gap-x-4">
-                    <ProviderIcon
-                      data-slot="list-item-extra-icon"
-                      id={i.id as IconName}
-                      // TODO: clean this up after we update icon in models.dev
-                      classList={{
-                        "text-icon-weak-base": true,
-                        "size-4 mx-0.5": i.id === "opencode",
-                        "size-5": i.id !== "opencode",
-                      }}
-                    />
+                  <div class="w-full flex items-center gap-x-3">
+                    <ProviderIcon data-slot="list-item-extra-icon" id={i.id as IconName} />
                     <span>{i.name}</span>
                     <Show when={i.id === "opencode"}>
                       <Tag>Recommended</Tag>

+ 1 - 2
packages/desktop/src/components/dialog-select-model.tsx

@@ -35,7 +35,6 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => {
       }
     >
       <List
-        class="px-2.5"
         search={{ placeholder: "Search models", autofocus: true }}
         emptyMessage="No model results"
         key={(x) => `${x.provider.id}:${x.id}`}
@@ -61,7 +60,7 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => {
         }}
       >
         {(i) => (
-          <div class="w-full flex items-center gap-x-2.5">
+          <div class="w-full flex items-center gap-x-3">
             <span>{i.name}</span>
             <Show when={i.provider.id === "opencode" && (!i.cost || i.cost?.input === 0)}>
               <Tag>Free</Tag>

+ 2 - 12
packages/desktop/src/components/dialog-select-provider.tsx

@@ -15,7 +15,6 @@ export const DialogSelectProvider: Component = () => {
   return (
     <Dialog title="Connect provider">
       <List
-        class="px-2.5"
         search={{ placeholder: "Search providers", autofocus: true }}
         activeIcon="plus-small"
         key={(x) => x?.id}
@@ -38,17 +37,8 @@ export const DialogSelectProvider: Component = () => {
         }}
       >
         {(i) => (
-          <div class="px-1.25 w-full flex items-center gap-x-4">
-            <ProviderIcon
-              data-slot="list-item-extra-icon"
-              id={i.id as IconName}
-              // TODO: clean this up after we update icon in models.dev
-              classList={{
-                "text-icon-weak-base": true,
-                "size-4 mx-0.5": i.id === "opencode",
-                "size-5": i.id !== "opencode",
-              }}
-            />
+          <div class="px-1.25 w-full flex items-center gap-x-3">
+            <ProviderIcon data-slot="list-item-extra-icon" id={i.id as IconName} />
             <span>{i.name}</span>
             <Show when={i.id === "opencode"}>
               <Tag>Recommended</Tag>

+ 35 - 23
packages/desktop/src/components/header.tsx

@@ -20,6 +20,7 @@ import { iife } from "@opencode-ai/util/iife"
 export function Header(props: {
   navigateToProject: (directory: string) => void
   navigateToSession: (session: Session | undefined) => void
+  onMobileMenuToggle?: () => void
 }) {
   const globalSync = useGlobalSync()
   const globalSDK = useGlobalSDK()
@@ -29,11 +30,19 @@ export function Header(props: {
 
   return (
     <header class="h-12 shrink-0 bg-background-base border-b border-border-weak-base flex" data-tauri-drag-region>
+      <button
+        type="button"
+        class="xl:hidden w-12 shrink-0 flex items-center justify-center border-r border-border-weak-base hover:bg-surface-raised-base-hover active:bg-surface-raised-base-active transition-colors"
+        onClick={props.onMobileMenuToggle}
+      >
+        <Icon name="menu" size="small" />
+      </button>
       <A
         href="/"
         classList={{
+          "hidden xl:flex": true,
           "w-12 shrink-0 px-4 py-3.5": true,
-          "flex items-center justify-start self-stretch": true,
+          "items-center justify-start self-stretch": true,
           "border-r border-border-weak-base": true,
         }}
         style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
@@ -46,30 +55,32 @@ export function Header(props: {
           {(directory) => {
             const currentDirectory = createMemo(() => base64Decode(directory()))
             const store = createMemo(() => globalSync.child(currentDirectory())[0])
-            const sessions = createMemo(() => store().session ?? [])
+            const sessions = createMemo(() => (store().session ?? []).filter((s) => !s.parentID))
             const currentSession = createMemo(() => sessions().find((s) => s.id === params.id))
             const shareEnabled = createMemo(() => store().config.share !== "disabled")
             return (
               <>
-                <div class="flex items-center gap-3">
-                  <div class="flex items-center gap-2">
-                    <Select
-                      options={layout.projects.list().map((project) => project.worktree)}
-                      current={currentDirectory()}
-                      label={(x) => getFilename(x)}
-                      onSelect={(x) => (x ? props.navigateToProject(x) : undefined)}
-                      class="text-14-regular text-text-base"
-                      variant="ghost"
-                    >
-                      {/* @ts-ignore */}
-                      {(i) => (
-                        <div class="flex items-center gap-2">
-                          <Icon name="folder" size="small" />
-                          <div class="text-text-strong">{getFilename(i)}</div>
-                        </div>
-                      )}
-                    </Select>
-                    <div class="text-text-weaker">/</div>
+                <div class="flex items-center gap-3 min-w-0">
+                  <div class="flex items-center gap-2 min-w-0">
+                    <div class="hidden xl:flex items-center gap-2">
+                      <Select
+                        options={layout.projects.list().map((project) => project.worktree)}
+                        current={currentDirectory()}
+                        label={(x) => getFilename(x)}
+                        onSelect={(x) => (x ? props.navigateToProject(x) : undefined)}
+                        class="text-14-regular text-text-base"
+                        variant="ghost"
+                      >
+                        {/* @ts-ignore */}
+                        {(i) => (
+                          <div class="flex items-center gap-2">
+                            <Icon name="folder" size="small" />
+                            <div class="text-text-strong">{getFilename(i)}</div>
+                          </div>
+                        )}
+                      </Select>
+                      <div class="text-text-weaker">/</div>
+                    </div>
                     <Select
                       options={sessions()}
                       current={currentSession()}
@@ -77,12 +88,13 @@ export function Header(props: {
                       label={(x) => x.title}
                       value={(x) => x.id}
                       onSelect={props.navigateToSession}
-                      class="text-14-regular text-text-base max-w-md"
+                      class="text-14-regular text-text-base max-w-[calc(100vw-180px)] md:max-w-md"
                       variant="ghost"
                     />
                   </div>
                   <Show when={currentSession()}>
                     <Tooltip
+                      class="hidden xl:block"
                       value={
                         <div class="flex items-center gap-2">
                           <span>New session</span>
@@ -98,7 +110,7 @@ export function Header(props: {
                 </div>
                 <div class="flex items-center gap-4">
                   <Tooltip
-                    class="shrink-0"
+                    class="hidden md:block shrink-0"
                     value={
                       <div class="flex items-center gap-2">
                         <span>Toggle terminal</span>

+ 6 - 2
packages/desktop/src/components/prompt-input.tsx

@@ -22,6 +22,7 @@ import { useProviders } from "@/hooks/use-providers"
 import { useCommand } from "@/context/command"
 import { persisted } from "@/utils/persist"
 import { Identifier } from "@/utils/id"
+import { SessionContextUsage } from "@/components/session-context-usage"
 
 const ACCEPTED_IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"]
 const ACCEPTED_FILE_TYPES = [...ACCEPTED_IMAGE_TYPES, "application/pdf"]
@@ -972,7 +973,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
             }}
           />
           <Show when={!prompt.dirty() && store.imageAttachments.length === 0}>
-            <div class="absolute top-0 left-0 px-5 py-3 text-14-regular text-text-weak pointer-events-none">
+            <div class="absolute top-0 inset-x-0 px-5 py-3 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate">
               {store.mode === "shell"
                 ? "Enter shell command..."
                 : `Ask anything... "${PLACEHOLDERS[store.placeholder]}"`}
@@ -1026,12 +1027,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
                     }
                   >
                     {local.model.current()?.name ?? "Select model"}
-                    <span class="ml-0.5 text-text-weak text-12-regular">{local.model.current()?.provider.name}</span>
+                    <span class="hidden md:block ml-0.5 text-text-weak text-12-regular">
+                      {local.model.current()?.provider.name}
+                    </span>
                     <Icon name="chevron-down" size="small" />
                   </Button>
                 </Tooltip>
               </Match>
             </Switch>
+            <SessionContextUsage />
           </div>
           <div class="flex items-center gap-1 absolute right-2 bottom-2">
             <input

+ 64 - 0
packages/desktop/src/components/session-context-usage.tsx

@@ -0,0 +1,64 @@
+import { createMemo, Show } from "solid-js"
+import { Tooltip } from "@opencode-ai/ui/tooltip"
+import { ProgressCircle } from "@opencode-ai/ui/progress-circle"
+import { useSync } from "@/context/sync"
+import { useParams } from "@solidjs/router"
+import { AssistantMessage } from "@opencode-ai/sdk/v2"
+
+export function SessionContextUsage() {
+  const sync = useSync()
+  const params = useParams()
+  const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : []))
+
+  const cost = createMemo(() => {
+    const total = messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0)
+    return new Intl.NumberFormat("en-US", {
+      style: "currency",
+      currency: "USD",
+    }).format(total)
+  })
+
+  const context = createMemo(() => {
+    const last = messages().findLast((x) => x.role === "assistant" && x.tokens.output > 0) as AssistantMessage
+    if (!last) return
+    const total =
+      last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write
+    const model = sync.data.provider.all.find((x) => x.id === last.providerID)?.models[last.modelID]
+    return {
+      tokens: total.toLocaleString(),
+      percentage: model?.limit.context ? Math.round((total / model.limit.context) * 100) : null,
+    }
+  })
+
+  return (
+    <Show when={context?.()}>
+      {(ctx) => (
+        <Tooltip
+          openDelay={300}
+          value={
+            <div class="flex flex-col gap-1 p-2">
+              <div class="flex justify-between gap-4">
+                <span class="text-text-weaker">Tokens</span>
+                <span class="text-text-strong">{ctx().tokens}</span>
+              </div>
+              <div class="flex justify-between gap-4">
+                <span class="text-text-weaker">Usage</span>
+                <span class="text-text-strong">{ctx().percentage ?? 0}%</span>
+              </div>
+              <div class="flex justify-between gap-4">
+                <span class="text-text-weaker">Cost</span>
+                <span class="text-text-strong">{cost()}</span>
+              </div>
+            </div>
+          }
+          placement="top"
+        >
+          <div class="flex items-center gap-1">
+            <span class="text-12-medium text-text-weak">{`${ctx().percentage ?? 0}%`}</span>
+            <ProgressCircle size={16} strokeWidth={2} percentage={ctx().percentage ?? 0} />
+          </div>
+        </Tooltip>
+      )}
+    </Show>
+  )
+}

+ 0 - 1
packages/desktop/src/context/command.tsx

@@ -119,7 +119,6 @@ function DialogCommand(props: { options: CommandOption[] }) {
   return (
     <Dialog title="Commands">
       <List
-        class="px-2.5"
         search={{ placeholder: "Search commands", autofocus: true }}
         emptyMessage="No commands found"
         items={() => props.options.filter((x) => !x.id.startsWith("suggested.") || !x.disabled)}

+ 4 - 2
packages/desktop/src/context/layout.tsx

@@ -108,10 +108,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
           setStore("projects", (x) => x.filter((x) => x.worktree !== directory))
         },
         expand(directory: string) {
-          setStore("projects", (x) => x.map((x) => (x.worktree === directory ? { ...x, expanded: true } : x)))
+          const index = store.projects.findIndex((x) => x.worktree === directory)
+          if (index !== -1) setStore("projects", index, "expanded", true)
         },
         collapse(directory: string) {
-          setStore("projects", (x) => x.map((x) => (x.worktree === directory ? { ...x, expanded: false } : x)))
+          const index = store.projects.findIndex((x) => x.worktree === directory)
+          if (index !== -1) setStore("projects", index, "expanded", false)
         },
         move(directory: string, toIndex: number) {
           setStore("projects", (projects) => {

+ 198 - 121
packages/desktop/src/pages/layout.tsx

@@ -1,4 +1,16 @@
-import { createEffect, createMemo, For, Match, onMount, ParentProps, Show, Switch, type JSX } from "solid-js"
+import {
+  createEffect,
+  createMemo,
+  createSignal,
+  For,
+  Match,
+  onCleanup,
+  onMount,
+  ParentProps,
+  Show,
+  Switch,
+  type JSX,
+} from "solid-js"
 import { DateTime } from "luxon"
 import { A, useNavigate, useParams } from "@solidjs/router"
 import { useLayout, getAvatarColors, LocalProject } from "@/context/layout"
@@ -42,9 +54,29 @@ export default function Layout(props: ParentProps) {
   const [store, setStore] = createStore({
     lastSession: {} as { [directory: string]: string },
     activeDraggable: undefined as string | undefined,
+    mobileSidebarOpen: false,
+    mobileProjectsExpanded: {} as Record<string, boolean>,
   })
 
+  const mobileSidebar = {
+    open: () => store.mobileSidebarOpen,
+    show: () => setStore("mobileSidebarOpen", true),
+    hide: () => setStore("mobileSidebarOpen", false),
+    toggle: () => setStore("mobileSidebarOpen", (x) => !x),
+  }
+
+  const mobileProjects = {
+    expanded: (directory: string) => store.mobileProjectsExpanded[directory] ?? true,
+    expand: (directory: string) => setStore("mobileProjectsExpanded", directory, true),
+    collapse: (directory: string) => setStore("mobileProjectsExpanded", directory, false),
+  }
+
   let scrollContainerRef: HTMLDivElement | undefined
+  const xlQuery = window.matchMedia("(min-width: 1280px)")
+  const [isLargeViewport, setIsLargeViewport] = createSignal(xlQuery.matches)
+  const handleViewportChange = (e: MediaQueryListEvent) => setIsLargeViewport(e.matches)
+  xlQuery.addEventListener("change", handleViewportChange)
+  onCleanup(() => xlQuery.removeEventListener("change", handleViewportChange))
 
   const params = useParams()
   const globalSDK = useGlobalSDK()
@@ -259,11 +291,13 @@ export default function Layout(props: ParentProps) {
     if (!directory) return
     const lastSession = store.lastSession[directory]
     navigate(`/${base64Encode(directory)}${lastSession ? `/session/${lastSession}` : ""}`)
+    mobileSidebar.hide()
   }
 
   function navigateToSession(session: Session | undefined) {
     if (!session) return
     navigate(`/${params.dir}/session/${session?.id}`)
+    mobileSidebar.hide()
   }
 
   function openProject(directory: string, navigate = true) {
@@ -302,8 +336,12 @@ export default function Layout(props: ParentProps) {
   })
 
   createEffect(() => {
-    const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 48
-    document.documentElement.style.setProperty("--dialog-left-margin", `${sidebarWidth}px`)
+    if (isLargeViewport()) {
+      const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 48
+      document.documentElement.style.setProperty("--dialog-left-margin", `${sidebarWidth}px`)
+    } else {
+      document.documentElement.style.setProperty("--dialog-left-margin", "0px")
+    }
   })
 
   function getDraggableId(event: unknown): string | undefined {
@@ -419,6 +457,7 @@ export default function Layout(props: ParentProps) {
     project: LocalProject
     depth?: number
     childrenMap: Map<string, Session[]>
+    mobile?: boolean
   }): JSX.Element => {
     const notification = useNotification()
     const depth = props.depth ?? 0
@@ -439,7 +478,7 @@ export default function Layout(props: ParentProps) {
                  hover:bg-surface-raised-base-hover focus-within:bg-surface-raised-base-hover has-[.active]:bg-surface-raised-base-hover"
           style={{ "padding-left": `${16 + depth * 12}px` }}
         >
-          <Tooltip placement="right" value={props.session.title} gutter={10}>
+          <Tooltip placement={props.mobile ? "bottom" : "right"} value={props.session.title} gutter={10}>
             <A
               href={`${props.slug}/session/${props.session.id}`}
               class="flex flex-col min-w-0 text-left w-full focus:outline-none"
@@ -486,7 +525,7 @@ export default function Layout(props: ParentProps) {
             </A>
           </Tooltip>
           <div class="hidden group-hover/session:flex group-active/session:flex group-focus-within/session:flex text-text-base gap-1 items-center absolute top-1 right-1">
-            <Tooltip placement="right" value="Archive session">
+            <Tooltip placement={props.mobile ? "bottom" : "right"} value="Archive session">
               <IconButton icon="archive" variant="ghost" onClick={() => archiveSession(props.session)} />
             </Tooltip>
           </div>
@@ -499,6 +538,7 @@ export default function Layout(props: ParentProps) {
               project={props.project}
               depth={depth + 1}
               childrenMap={props.childrenMap}
+              mobile={props.mobile}
             />
           )}
         </For>
@@ -506,8 +546,9 @@ export default function Layout(props: ParentProps) {
     )
   }
 
-  const SortableProject = (props: { project: LocalProject }): JSX.Element => {
+  const SortableProject = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => {
     const sortable = createSortable(props.project.worktree)
+    const showExpanded = createMemo(() => props.mobile || layout.sidebar.opened())
     const slug = createMemo(() => base64Encode(props.project.worktree))
     const name = createMemo(() => getFilename(props.project.worktree))
     const [store, setProjectStore] = globalSync.child(props.project.worktree)
@@ -531,21 +572,24 @@ export default function Layout(props: ParentProps) {
       setProjectStore("limit", (limit) => limit + 5)
       await globalSync.project.loadSessions(props.project.worktree)
     }
+    const isExpanded = createMemo(() =>
+      props.mobile ? mobileProjects.expanded(props.project.worktree) : props.project.expanded,
+    )
     const handleOpenChange = (open: boolean) => {
-      if (open) layout.projects.expand(props.project.worktree)
-      else layout.projects.collapse(props.project.worktree)
+      if (props.mobile) {
+        if (open) mobileProjects.expand(props.project.worktree)
+        else mobileProjects.collapse(props.project.worktree)
+      } else {
+        if (open) layout.projects.expand(props.project.worktree)
+        else layout.projects.collapse(props.project.worktree)
+      }
     }
     return (
       // @ts-ignore
       <div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
         <Switch>
-          <Match when={layout.sidebar.opened()}>
-            <Collapsible
-              variant="ghost"
-              open={props.project.expanded}
-              class="gap-2 shrink-0"
-              onOpenChange={handleOpenChange}
-            >
+          <Match when={showExpanded()}>
+            <Collapsible variant="ghost" open={isExpanded()} class="gap-2 shrink-0" onOpenChange={handleOpenChange}>
               <Button
                 as={"div"}
                 variant="ghost"
@@ -556,7 +600,7 @@ export default function Layout(props: ParentProps) {
                     project={props.project}
                     class="group-hover/session:hidden"
                     expandable
-                    notify={!props.project.expanded}
+                    notify={!isExpanded()}
                   />
                   <span class="truncate text-14-medium text-text-strong">{name()}</span>
                 </Collapsible.Trigger>
@@ -585,6 +629,7 @@ export default function Layout(props: ParentProps) {
                         slug={slug()}
                         project={props.project}
                         childrenMap={childSessionsByParent()}
+                        mobile={props.mobile}
                       />
                     )}
                   </For>
@@ -595,7 +640,7 @@ export default function Layout(props: ParentProps) {
                     >
                       <div class="flex items-center self-stretch w-full">
                         <div class="flex-1 min-w-0">
-                          <Tooltip placement="right" value="New session">
+                          <Tooltip placement={props.mobile ? "bottom" : "right"} value="New session">
                             <A
                               href={`${slug()}/session`}
                               class="flex flex-col gap-1 min-w-0 text-left w-full focus:outline-none"
@@ -650,30 +695,12 @@ export default function Layout(props: ParentProps) {
     )
   }
 
-  return (
-    <div class="relative flex-1 min-h-0 flex flex-col">
-      <Header navigateToProject={navigateToProject} navigateToSession={navigateToSession} />
-      <div class="flex-1 min-h-0 flex">
-        <div
-          classList={{
-            "relative @container w-12 pb-5 shrink-0 bg-background-base": true,
-            "flex flex-col gap-5.5 items-start self-stretch justify-between": true,
-            "border-r border-border-weak-base contain-strict": true,
-          }}
-          style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
-        >
-          <Show when={layout.sidebar.opened()}>
-            <ResizeHandle
-              direction="horizontal"
-              size={layout.sidebar.width()}
-              min={150}
-              max={window.innerWidth * 0.3}
-              collapseThreshold={80}
-              onResize={layout.sidebar.resize}
-              onCollapse={layout.sidebar.close}
-            />
-          </Show>
-          <div class="flex flex-col items-start self-stretch gap-4 p-2 min-h-0 overflow-hidden">
+  const SidebarContent = (sidebarProps: { mobile?: boolean }) => {
+    const expanded = () => sidebarProps.mobile || layout.sidebar.opened()
+    return (
+      <>
+        <div class="flex flex-col items-start self-stretch gap-4 p-2 min-h-0 overflow-hidden">
+          <Show when={!sidebarProps.mobile}>
             <Tooltip
               class="shrink-0"
               placement="right"
@@ -683,7 +710,7 @@ export default function Layout(props: ParentProps) {
                   <span class="text-icon-base text-12-medium">{command.keybind("sidebar.toggle")}</span>
                 </div>
               }
-              inactive={layout.sidebar.opened()}
+              inactive={expanded()}
             >
               <Button
                 variant="ghost"
@@ -715,110 +742,160 @@ export default function Layout(props: ParentProps) {
                 </Show>
               </Button>
             </Tooltip>
-            <DragDropProvider
-              onDragStart={handleDragStart}
-              onDragEnd={handleDragEnd}
-              onDragOver={handleDragOver}
-              collisionDetector={closestCenter}
+          </Show>
+          <DragDropProvider
+            onDragStart={handleDragStart}
+            onDragEnd={handleDragEnd}
+            onDragOver={handleDragOver}
+            collisionDetector={closestCenter}
+          >
+            <DragDropSensors />
+            <ConstrainDragXAxis />
+            <div
+              ref={sidebarProps.mobile ? undefined : scrollContainerRef}
+              class="w-full min-w-8 flex flex-col gap-2 min-h-0 overflow-y-auto no-scrollbar"
             >
-              <DragDropSensors />
-              <ConstrainDragXAxis />
-              <div
-                ref={scrollContainerRef}
-                class="w-full min-w-8 flex flex-col gap-2 min-h-0 overflow-y-auto no-scrollbar"
-              >
-                <SortableProvider ids={layout.projects.list().map((p) => p.worktree)}>
-                  <For each={layout.projects.list()}>{(project) => <SortableProject project={project} />}</For>
-                </SortableProvider>
-              </div>
-              <DragOverlay>
-                <ProjectDragOverlay />
-              </DragOverlay>
-            </DragDropProvider>
-          </div>
-          <div class="flex flex-col gap-1.5 self-stretch items-start shrink-0 px-2 py-3">
-            <Switch>
-              <Match when={!providers.paid().length && layout.sidebar.opened()}>
-                <div class="rounded-md bg-background-stronger shadow-xs-border-base">
-                  <div class="p-3 flex flex-col gap-2">
-                    <div class="text-12-medium text-text-strong">Getting started</div>
-                    <div class="text-text-base">OpenCode includes free models so you can start immediately.</div>
-                    <div class="text-text-base">Connect any provider to use models, inc. Claude, GPT, Gemini etc.</div>
-                  </div>
-                  <Tooltip placement="right" value="Connect provider" inactive={layout.sidebar.opened()}>
-                    <Button
-                      class="flex w-full text-left justify-start text-12-medium text-text-strong stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-2.25 pb-px"
-                      size="large"
-                      icon="plus"
-                      onClick={connectProvider}
-                    >
-                      <Show when={layout.sidebar.opened()}>Connect provider</Show>
-                    </Button>
-                  </Tooltip>
+              <SortableProvider ids={layout.projects.list().map((p) => p.worktree)}>
+                <For each={layout.projects.list()}>
+                  {(project) => <SortableProject project={project} mobile={sidebarProps.mobile} />}
+                </For>
+              </SortableProvider>
+            </div>
+            <DragOverlay>
+              <ProjectDragOverlay />
+            </DragOverlay>
+          </DragDropProvider>
+        </div>
+        <div class="flex flex-col gap-1.5 self-stretch items-start shrink-0 px-2 py-3">
+          <Switch>
+            <Match when={!providers.paid().length && expanded()}>
+              <div class="rounded-md bg-background-stronger shadow-xs-border-base">
+                <div class="p-3 flex flex-col gap-2">
+                  <div class="text-12-medium text-text-strong">Getting started</div>
+                  <div class="text-text-base">OpenCode includes free models so you can start immediately.</div>
+                  <div class="text-text-base">Connect any provider to use models, inc. Claude, GPT, Gemini etc.</div>
                 </div>
-              </Match>
-              <Match when={true}>
-                <Tooltip placement="right" value="Connect provider" inactive={layout.sidebar.opened()}>
+                <Tooltip placement="right" value="Connect provider" inactive={expanded()}>
                   <Button
-                    class="flex w-full text-left justify-start text-text-base stroke-[1.5px] rounded-lg px-2"
-                    variant="ghost"
+                    class="flex w-full text-left justify-start text-12-medium text-text-strong stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-2.25 pb-px"
                     size="large"
                     icon="plus"
                     onClick={connectProvider}
                   >
-                    <Show when={layout.sidebar.opened()}>Connect provider</Show>
+                    Connect provider
                   </Button>
                 </Tooltip>
-              </Match>
-            </Switch>
-            <Show when={platform.openDirectoryPickerDialog}>
-              <Tooltip
-                placement="right"
-                value={
-                  <div class="flex items-center gap-2">
-                    <span>Open project</span>
-                    <span class="text-icon-base text-12-medium">{command.keybind("project.open")}</span>
-                  </div>
-                }
-                inactive={layout.sidebar.opened()}
-              >
+              </div>
+            </Match>
+            <Match when={true}>
+              <Tooltip placement="right" value="Connect provider" inactive={expanded()}>
                 <Button
                   class="flex w-full text-left justify-start text-text-base stroke-[1.5px] rounded-lg px-2"
                   variant="ghost"
                   size="large"
-                  icon="folder-add-left"
-                  onClick={chooseProject}
+                  icon="plus"
+                  onClick={connectProvider}
                 >
-                  <Show when={layout.sidebar.opened()}>Open project</Show>
+                  <Show when={expanded()}>Connect provider</Show>
                 </Button>
               </Tooltip>
-            </Show>
-            {/* <Tooltip placement="right" value="Settings" inactive={layout.sidebar.opened()}> */}
-            {/*   <Button */}
-            {/*     disabled */}
-            {/*     class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2" */}
-            {/*     variant="ghost" */}
-            {/*     size="large" */}
-            {/*     icon="settings-gear" */}
-            {/*   > */}
-            {/*     <Show when={layout.sidebar.opened()}>Settings</Show> */}
-            {/*   </Button> */}
-            {/* </Tooltip> */}
-            <Tooltip placement="right" value="Share feedback" inactive={layout.sidebar.opened()}>
+            </Match>
+          </Switch>
+          <Show when={platform.openDirectoryPickerDialog}>
+            <Tooltip
+              placement="right"
+              value={
+                <div class="flex items-center gap-2">
+                  <span>Open project</span>
+                  <Show when={!sidebarProps.mobile}>
+                    <span class="text-icon-base text-12-medium">{command.keybind("project.open")}</span>
+                  </Show>
+                </div>
+              }
+              inactive={expanded()}
+            >
               <Button
-                as={"a"}
-                href="https://opencode.ai/desktop-feedback"
-                target="_blank"
                 class="flex w-full text-left justify-start text-text-base stroke-[1.5px] rounded-lg px-2"
                 variant="ghost"
                 size="large"
-                icon="bubble-5"
+                icon="folder-add-left"
+                onClick={chooseProject}
               >
-                <Show when={layout.sidebar.opened()}>Share feedback</Show>
+                <Show when={expanded()}>Open project</Show>
               </Button>
             </Tooltip>
+          </Show>
+          <Tooltip placement="right" value="Share feedback" inactive={expanded()}>
+            <Button
+              as={"a"}
+              href="https://opencode.ai/desktop-feedback"
+              target="_blank"
+              class="flex w-full text-left justify-start text-text-base stroke-[1.5px] rounded-lg px-2"
+              variant="ghost"
+              size="large"
+              icon="bubble-5"
+            >
+              <Show when={expanded()}>Share feedback</Show>
+            </Button>
+          </Tooltip>
+        </div>
+      </>
+    )
+  }
+
+  return (
+    <div class="relative flex-1 min-h-0 flex flex-col">
+      <Header
+        navigateToProject={navigateToProject}
+        navigateToSession={navigateToSession}
+        onMobileMenuToggle={mobileSidebar.toggle}
+      />
+      <div class="flex-1 min-h-0 flex">
+        <div
+          classList={{
+            "hidden xl:flex": true,
+            "relative @container w-12 pb-5 shrink-0 bg-background-base": true,
+            "flex-col gap-5.5 items-start self-stretch justify-between": true,
+            "border-r border-border-weak-base contain-strict": true,
+          }}
+          style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
+        >
+          <Show when={layout.sidebar.opened()}>
+            <ResizeHandle
+              direction="horizontal"
+              size={layout.sidebar.width()}
+              min={150}
+              max={window.innerWidth * 0.3}
+              collapseThreshold={80}
+              onResize={layout.sidebar.resize}
+              onCollapse={layout.sidebar.close}
+            />
+          </Show>
+          <SidebarContent />
+        </div>
+        <div class="xl:hidden">
+          <div
+            classList={{
+              "fixed inset-0 bg-black/50 z-40 transition-opacity duration-200": true,
+              "opacity-100 pointer-events-auto": mobileSidebar.open(),
+              "opacity-0 pointer-events-none": !mobileSidebar.open(),
+            }}
+            onClick={(e) => {
+              if (e.target === e.currentTarget) mobileSidebar.hide()
+            }}
+          />
+          <div
+            classList={{
+              "@container fixed inset-y-0 left-0 z-50 w-72 bg-background-base border-r border-border-weak-base flex flex-col gap-5.5 items-start self-stretch justify-between pt-12 pb-5 transition-transform duration-200 ease-out": true,
+              "translate-x-0": mobileSidebar.open(),
+              "-translate-x-full": !mobileSidebar.open(),
+            }}
+            onClick={(e) => e.stopPropagation()}
+          >
+            <SidebarContent mobile />
           </div>
         </div>
+
         <main class="size-full overflow-x-hidden flex flex-col items-start contain-strict">{props.children}</main>
       </div>
       <Toast.Region />

+ 167 - 76
packages/desktop/src/pages/session.tsx

@@ -12,6 +12,7 @@ import {
   createRenderEffect,
   batch,
 } from "solid-js"
+
 import { Dynamic } from "solid-js/web"
 import { useLocal, type LocalFile } from "@/context/local"
 import { createStore } from "solid-js/store"
@@ -26,6 +27,7 @@ import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
 import { Tabs } from "@opencode-ai/ui/tabs"
 import { useCodeComponent } from "@opencode-ai/ui/context/code"
 import { SessionTurn } from "@opencode-ai/ui/session-turn"
+import { createAutoScroll } from "@opencode-ai/ui/hooks"
 import { SessionMessageRail } from "@opencode-ai/ui/session-message-rail"
 import { SessionReview } from "@opencode-ai/ui/session-review"
 import {
@@ -70,7 +72,6 @@ export default function Page() {
 
   const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
   const tabs = createMemo(() => layout.tabs(sessionKey()))
-
   const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
   const revertMessageID = createMemo(() => info()?.revert?.messageID)
   const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : []))
@@ -79,7 +80,6 @@ export default function Page() {
       .filter((m) => m.role === "user")
       .sort((a, b) => a.id.localeCompare(b.id)),
   )
-  // Visible user messages excludes reverted messages (those >= revertMessageID)
   const visibleUserMessages = createMemo(() => {
     const revert = revertMessageID()
     if (!revert) return userMessages()
@@ -87,15 +87,24 @@ export default function Page() {
   })
   const lastUserMessage = createMemo(() => visibleUserMessages()?.at(-1))
 
-  const [messageStore, setMessageStore] = createStore<{ messageId?: string }>({})
+  const [store, setStore] = createStore({
+    clickTimer: undefined as number | undefined,
+    activeDraggable: undefined as string | undefined,
+    activeTerminalDraggable: undefined as string | undefined,
+    userInteracted: false,
+    stepsExpanded: true,
+    mobileStepsExpanded: {} as Record<string, boolean>,
+    messageId: undefined as string | undefined,
+  })
+
   const activeMessage = createMemo(() => {
-    if (!messageStore.messageId) return lastUserMessage()
+    if (!store.messageId) return lastUserMessage()
     // If the stored message is no longer visible (e.g., was reverted), fall back to last visible
-    const found = visibleUserMessages()?.find((m) => m.id === messageStore.messageId)
+    const found = visibleUserMessages()?.find((m) => m.id === store.messageId)
     return found ?? lastUserMessage()
   })
   const setActiveMessage = (message: UserMessage | undefined) => {
-    setMessageStore("messageId", message?.id)
+    setStore("messageId", message?.id)
   }
 
   function navigateMessageByOffset(offset: number) {
@@ -119,13 +128,6 @@ export default function Page() {
 
   const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : []))
 
-  const [store, setStore] = createStore({
-    clickTimer: undefined as number | undefined,
-    activeDraggable: undefined as string | undefined,
-    activeTerminalDraggable: undefined as string | undefined,
-    userInteracted: false,
-    stepsExpanded: true,
-  })
   let inputRef!: HTMLDivElement
 
   createEffect(() => {
@@ -146,7 +148,7 @@ export default function Page() {
       () => visibleUserMessages().at(-1)?.id,
       (lastId, prevLastId) => {
         if (lastId && prevLastId && lastId > prevLastId) {
-          setMessageStore("messageId", undefined)
+          setStore("messageId", undefined)
         }
       },
       { defer: true },
@@ -533,72 +535,161 @@ export default function Page() {
 
   const showTabs = createMemo(() => diffs().length > 0 || tabs().all().length > 0)
 
+  const mobileWorking = createMemo(() => status().type !== "idle")
+  const mobileAutoScroll = createAutoScroll({
+    working: mobileWorking,
+    onUserInteracted: () => setStore("userInteracted", true),
+  })
+
+  const MobileTurns = () => (
+    <div
+      ref={mobileAutoScroll.scrollRef}
+      onScroll={mobileAutoScroll.handleScroll}
+      onClick={mobileAutoScroll.handleInteraction}
+      class="relative mt-2 min-w-0 w-full h-full overflow-y-auto no-scrollbar pb-12"
+    >
+      <div ref={mobileAutoScroll.contentRef} class="flex flex-col gap-45 items-start justify-start mt-4">
+        <For each={visibleUserMessages()}>
+          {(message) => (
+            <SessionTurn
+              sessionID={params.id!}
+              messageID={message.id}
+              stepsExpanded={store.mobileStepsExpanded[message.id] ?? false}
+              onStepsExpandedToggle={() => setStore("mobileStepsExpanded", message.id, (x) => !x)}
+              onUserInteracted={() => setStore("userInteracted", true)}
+              classes={{
+                root: "min-w-0 w-full relative",
+                content:
+                  "flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]",
+                container: "px-4",
+              }}
+            />
+          )}
+        </For>
+      </div>
+    </div>
+  )
+
+  const NewSessionView = () => (
+    <div class="size-full flex flex-col pb-45 justify-end items-start gap-4 flex-[1_0_0] self-stretch max-w-200 mx-auto px-6">
+      <div class="text-20-medium text-text-weaker">New session</div>
+      <div class="flex justify-center items-center gap-3">
+        <Icon name="folder" size="small" />
+        <div class="text-12-medium text-text-weak">
+          {getDirectory(sync.data.path.directory)}
+          <span class="text-text-strong">{getFilename(sync.data.path.directory)}</span>
+        </div>
+      </div>
+      <Show when={sync.project}>
+        {(project) => (
+          <div class="flex justify-center items-center gap-3">
+            <Icon name="pencil-line" size="small" />
+            <div class="text-12-medium text-text-weak">
+              Last modified&nbsp;
+              <span class="text-text-strong">
+                {DateTime.fromMillis(project().time.updated ?? project().time.created).toRelative()}
+              </span>
+            </div>
+          </div>
+        )}
+      </Show>
+    </div>
+  )
+
+  const DesktopSessionContent = () => (
+    <Switch>
+      <Match when={params.id}>
+        <div class="flex items-start justify-start h-full min-h-0">
+          <SessionMessageRail
+            messages={visibleUserMessages()}
+            current={activeMessage()}
+            onMessageSelect={setActiveMessage}
+            wide={!showTabs()}
+          />
+          <Show when={activeMessage()}>
+            <SessionTurn
+              sessionID={params.id!}
+              messageID={activeMessage()!.id}
+              stepsExpanded={store.stepsExpanded}
+              onStepsExpandedToggle={() => setStore("stepsExpanded", (x) => !x)}
+              onUserInteracted={() => setStore("userInteracted", true)}
+              classes={{
+                root: "pb-20 flex-1 min-w-0",
+                content: "pb-20",
+                container:
+                  "w-full " +
+                  (!showTabs() ? "max-w-200 mx-auto px-6" : visibleUserMessages().length > 1 ? "pr-6 pl-18" : "px-6"),
+              }}
+            />
+          </Show>
+        </div>
+      </Match>
+      <Match when={true}>
+        <NewSessionView />
+      </Match>
+    </Switch>
+  )
+
   return (
     <div class="relative bg-background-base size-full overflow-hidden flex flex-col">
-      <div class="min-h-0 grow w-full flex">
-        {/* Session pane - always visible */}
+      <div class="md:hidden flex-1 min-h-0 flex flex-col bg-background-stronger">
+        <Switch>
+          <Match when={!params.id}>
+            <div class="flex-1 min-h-0 overflow-hidden">
+              <NewSessionView />
+            </div>
+          </Match>
+          <Match when={diffs().length > 0}>
+            <Tabs class="flex-1 min-h-0 flex flex-col pb-28">
+              <Tabs.List>
+                <Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}>
+                  Session
+                </Tabs.Trigger>
+                <Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}>
+                  {diffs().length} Files Changed
+                </Tabs.Trigger>
+              </Tabs.List>
+              <Tabs.Content value="session" class="flex-1 !overflow-hidden">
+                <MobileTurns />
+              </Tabs.Content>
+              <Tabs.Content forceMount value="review" class="flex-1 !overflow-hidden hidden data-[selected]:block">
+                <div class="relative h-full mt-6 overflow-y-auto no-scrollbar">
+                  <SessionReview
+                    diffs={diffs()}
+                    classes={{
+                      root: "pb-32",
+                      header: "px-4",
+                      container: "px-4",
+                    }}
+                  />
+                </div>
+              </Tabs.Content>
+            </Tabs>
+          </Match>
+          <Match when={true}>
+            <div class="flex-1 min-h-0 overflow-hidden">
+              <MobileTurns />
+            </div>
+          </Match>
+        </Switch>
+        <div class="absolute inset-x-0 bottom-4 flex flex-col justify-center items-center z-50 px-4">
+          <div class="w-full">
+            <PromptInput
+              ref={(el) => {
+                inputRef = el
+              }}
+            />
+          </div>
+        </div>
+      </div>
+
+      <div class="hidden md:flex min-h-0 grow w-full">
         <div
           class="@container relative shrink-0 py-3 flex flex-col gap-6 min-h-0 h-full bg-background-stronger"
           style={{ width: showTabs() ? `${layout.session.width()}px` : "100%" }}
         >
           <div class="flex-1 min-h-0 overflow-hidden">
-            <Switch>
-              <Match when={params.id}>
-                <div class="flex items-start justify-start h-full min-h-0">
-                  <SessionMessageRail
-                    messages={visibleUserMessages()}
-                    current={activeMessage()}
-                    onMessageSelect={setActiveMessage}
-                    wide={!showTabs()}
-                  />
-                  <Show when={activeMessage()}>
-                    <SessionTurn
-                      sessionID={params.id!}
-                      messageID={activeMessage()!.id}
-                      stepsExpanded={store.stepsExpanded}
-                      onStepsExpandedToggle={() => setStore("stepsExpanded", (x) => !x)}
-                      onUserInteracted={() => setStore("userInteracted", true)}
-                      classes={{
-                        root: "pb-20 flex-1 min-w-0",
-                        content: "pb-20",
-                        container:
-                          "w-full " +
-                          (!showTabs()
-                            ? "max-w-200 mx-auto px-6"
-                            : visibleUserMessages().length > 1
-                              ? "pr-6 pl-18"
-                              : "px-6"),
-                      }}
-                    />
-                  </Show>
-                </div>
-              </Match>
-              <Match when={true}>
-                <div class="size-full flex flex-col pb-45 justify-end items-start gap-4 flex-[1_0_0] self-stretch max-w-200 mx-auto px-6">
-                  <div class="text-20-medium text-text-weaker">New session</div>
-                  <div class="flex justify-center items-center gap-3">
-                    <Icon name="folder" size="small" />
-                    <div class="text-12-medium text-text-weak">
-                      {getDirectory(sync.data.path.directory)}
-                      <span class="text-text-strong">{getFilename(sync.data.path.directory)}</span>
-                    </div>
-                  </div>
-                  <Show when={sync.project}>
-                    {(project) => (
-                      <div class="flex justify-center items-center gap-3">
-                        <Icon name="pencil-line" size="small" />
-                        <div class="text-12-medium text-text-weak">
-                          Last modified&nbsp;
-                          <span class="text-text-strong">
-                            {DateTime.fromMillis(project().time.updated ?? project().time.created).toRelative()}
-                          </span>
-                        </div>
-                      </div>
-                    )}
-                  </Show>
-                </div>
-              </Match>
-            </Switch>
+            <DesktopSessionContent />
           </div>
           <div class="absolute inset-x-0 bottom-8 flex flex-col justify-center items-center z-50">
             <div
@@ -625,7 +716,6 @@ export default function Page() {
           </Show>
         </div>
 
-        {/* Tabs pane - visible when there are diffs or file tabs */}
         <Show when={showTabs()}>
           <div class="relative flex-1 min-w-0 h-full border-l border-border-weak-base">
             <DragDropProvider
@@ -683,7 +773,7 @@ export default function Page() {
                 </div>
                 <Show when={diffs().length}>
                   <Tabs.Content value="review" class="select-text flex flex-col h-full overflow-hidden contain-strict">
-                    <div class="relative pt-3 flex-1 min-h-0 overflow-hidden">
+                    <div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
                       <SessionReview
                         classes={{
                           root: "pb-40",
@@ -754,9 +844,10 @@ export default function Page() {
           </div>
         </Show>
       </div>
+
       <Show when={layout.terminal.opened()}>
         <div
-          class="relative w-full flex flex-col shrink-0 border-t border-border-weak-base"
+          class="hidden md:flex relative w-full flex-col shrink-0 border-t border-border-weak-base"
           style={{ height: `${layout.terminal.height()}px` }}
         >
           <ResizeHandle

+ 1 - 1
packages/enterprise/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/enterprise",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "private": true,
   "type": "module",
   "scripts": {

+ 23 - 11
packages/enterprise/src/routes/share/[shareID].tsx

@@ -212,6 +212,7 @@ export default function () {
                       {iife(() => {
                         const [store, setStore] = createStore({
                           messageId: undefined as string | undefined,
+                          expandedSteps: {} as Record<string, boolean>,
                         })
                         const messages = createMemo(() =>
                           data().sessionID
@@ -253,20 +254,22 @@ export default function () {
 
                         const title = () => (
                           <div class="flex flex-col gap-4">
-                            <div class="h-8 flex gap-4 items-center justify-start self-stretch">
-                              <div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
+                            <div class="flex flex-col gap-2 sm:flex-row sm:gap-4 sm:items-center sm:h-8 justify-start self-stretch">
+                              <div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base w-fit">
                                 <Mark class="shrink-0 w-3 my-0.5" />
                                 <div class="text-12-mono text-text-base">v{info().version}</div>
                               </div>
-                              <div class="flex gap-2 items-center">
-                                <ProviderIcon
-                                  id={provider() as IconName}
-                                  class="size-3.5 shrink-0 text-icon-strong-base"
-                                />
-                                <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
-                              </div>
-                              <div class="text-12-regular text-text-weaker">
-                                {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
+                              <div class="flex gap-4 items-center">
+                                <div class="flex gap-2 items-center">
+                                  <ProviderIcon
+                                    id={provider() as IconName}
+                                    class="size-3.5 shrink-0 text-icon-strong-base"
+                                  />
+                                  <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
+                                </div>
+                                <div class="text-12-regular text-text-weaker">
+                                  {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
+                                </div>
                               </div>
                             </div>
                             <div class="text-left text-16-medium text-text-strong">{info().title}</div>
@@ -282,6 +285,8 @@ export default function () {
                                   <SessionTurn
                                     sessionID={data().sessionID}
                                     messageID={message.id}
+                                    stepsExpanded={store.expandedSteps[message.id] ?? false}
+                                    onStepsExpandedToggle={() => setStore("expandedSteps", message.id, (v) => !v)}
                                     classes={{
                                       root: "min-w-0 w-full relative",
                                       content:
@@ -359,6 +364,13 @@ export default function () {
                                     <SessionTurn
                                       sessionID={data().sessionID}
                                       messageID={store.messageId ?? firstUserMessage()!.id!}
+                                      stepsExpanded={
+                                        store.expandedSteps[store.messageId ?? firstUserMessage()!.id!] ?? false
+                                      }
+                                      onStepsExpandedToggle={() => {
+                                        const id = store.messageId ?? firstUserMessage()!.id!
+                                        setStore("expandedSteps", id, (v) => !v)
+                                      }}
                                       classes={{
                                         root: "grow",
                                         content: "flex flex-col justify-between",

+ 6 - 6
packages/extensions/zed/extension.toml

@@ -1,7 +1,7 @@
 id = "opencode"
 name = "OpenCode"
 description = "The open source coding agent."
-version = "1.0.185"
+version = "1.0.187"
 schema_version = 1
 authors = ["Anomaly"]
 repository = "https://github.com/sst/opencode"
@@ -11,26 +11,26 @@ name = "OpenCode"
 icon = "./icons/opencode.svg"
 
 [agent_servers.opencode.targets.darwin-aarch64]
-archive = "https://github.com/sst/opencode/releases/download/v1.0.185/opencode-darwin-arm64.zip"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.187/opencode-darwin-arm64.zip"
 cmd = "./opencode"
 args = ["acp"]
 
 [agent_servers.opencode.targets.darwin-x86_64]
-archive = "https://github.com/sst/opencode/releases/download/v1.0.185/opencode-darwin-x64.zip"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.187/opencode-darwin-x64.zip"
 cmd = "./opencode"
 args = ["acp"]
 
 [agent_servers.opencode.targets.linux-aarch64]
-archive = "https://github.com/sst/opencode/releases/download/v1.0.185/opencode-linux-arm64.tar.gz"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.187/opencode-linux-arm64.tar.gz"
 cmd = "./opencode"
 args = ["acp"]
 
 [agent_servers.opencode.targets.linux-x86_64]
-archive = "https://github.com/sst/opencode/releases/download/v1.0.185/opencode-linux-x64.tar.gz"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.187/opencode-linux-x64.tar.gz"
 cmd = "./opencode"
 args = ["acp"]
 
 [agent_servers.opencode.targets.windows-x86_64]
-archive = "https://github.com/sst/opencode/releases/download/v1.0.185/opencode-windows-x64.zip"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.187/opencode-windows-x64.zip"
 cmd = "./opencode.exe"
 args = ["acp"]

+ 1 - 1
packages/function/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/function",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "$schema": "https://json.schemastore.org/package.json",
   "private": true,
   "type": "module",

+ 5 - 3
packages/opencode/package.json

@@ -1,6 +1,6 @@
 {
   "$schema": "https://json.schemastore.org/package.json",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "name": "opencode",
   "type": "module",
   "private": true,
@@ -55,10 +55,12 @@
     "@ai-sdk/google": "2.0.44",
     "@ai-sdk/google-vertex": "3.0.81",
     "@ai-sdk/mcp": "0.0.8",
+    "@ai-sdk/mistral": "2.0.26",
     "@ai-sdk/openai": "2.0.71",
     "@ai-sdk/openai-compatible": "1.0.27",
     "@ai-sdk/provider": "2.0.0",
     "@ai-sdk/provider-utils": "3.0.18",
+    "@ai-sdk/xai": "2.0.42",
     "@clack/prompts": "1.0.0-alpha.1",
     "@hono/standard-validator": "0.1.5",
     "@hono/zod-validator": "catalog:",
@@ -71,8 +73,8 @@
     "@opencode-ai/sdk": "workspace:*",
     "@opencode-ai/util": "workspace:*",
     "@openrouter/ai-sdk-provider": "1.5.2",
-    "@opentui/core": "0.1.62",
-    "@opentui/solid": "0.1.62",
+    "@opentui/core": "0.1.63",
+    "@opentui/solid": "0.1.63",
     "@parcel/watcher": "2.5.1",
     "@pierre/diffs": "catalog:",
     "@solid-primitives/event-bus": "1.1.2",

+ 1 - 1
packages/opencode/script/publish.ts

@@ -40,7 +40,7 @@ const tags = [Script.channel]
 
 const tasks = Object.entries(binaries).map(async ([name]) => {
   if (process.platform !== "win32") {
-    await $`chmod 755 -R .`.cwd(`./dist/${name}`)
+    await $`chmod -R 755 .`.cwd(`./dist/${name}`)
   }
   await $`bun pm pack`.cwd(`./dist/${name}`)
   for (const tag of tags) {

+ 10 - 4
packages/opencode/src/agent/prompt/summary.txt

@@ -1,4 +1,10 @@
-Summarize the following conversation into 2 sentences MAX explaining what the
-assistant did and why
-Do not explain the user's input.
-Do not speak in the third person about the assistant.
+Summarize what was done in this conversation. Write like a pull request description.
+
+Rules:
+- 2-3 sentences max
+- Describe the changes made, not the process
+- Do not mention running tests, builds, or other validation steps
+- Do not explain what the user asked for
+- Write in first person (I added..., I fixed...)
+- Never ask questions or add new questions
+- Only exception: if the conversation ends with an unanswered question to the user, preserve that exact question

+ 67 - 34
packages/opencode/src/cli/cmd/github.ts

@@ -7,7 +7,7 @@ import { graphql } from "@octokit/graphql"
 import * as core from "@actions/core"
 import * as github from "@actions/github"
 import type { Context } from "@actions/github/lib/context"
-import type { IssueCommentEvent, PullRequestReviewCommentEvent } from "@octokit/webhooks-types"
+import type { IssueCommentEvent, PullRequestReviewCommentEvent, PullRequestEvent } from "@octokit/webhooks-types"
 import { UI } from "../ui"
 import { cmd } from "./cmd"
 import { ModelsDev } from "../../provider/models"
@@ -127,7 +127,7 @@ type IssueQueryResponse = {
 const AGENT_USERNAME = "opencode-agent[bot]"
 const AGENT_REACTION = "eyes"
 const WORKFLOW_FILE = ".github/workflows/opencode.yml"
-const SUPPORTED_EVENTS = ["issue_comment", "pull_request_review_comment", "schedule"] as const
+const SUPPORTED_EVENTS = ["issue_comment", "pull_request_review_comment", "schedule", "pull_request"] as const
 
 // Parses GitHub remote URLs in various formats:
 // - https://github.com/owner/repo.git
@@ -392,6 +392,7 @@ export const GithubRunCommand = cmd({
         core.setFailed(`Unsupported event type: ${context.eventName}`)
         process.exit(1)
       }
+      const isCommentEvent = ["issue_comment", "pull_request_review_comment"].includes(context.eventName)
       const isScheduleEvent = context.eventName === "schedule"
 
       const { providerID, modelID } = normalizeModel()
@@ -400,17 +401,17 @@ export const GithubRunCommand = cmd({
       const oidcBaseUrl = normalizeOidcBaseUrl()
       const { owner, repo } = context.repo
       // For schedule events, payload has no issue/comment data
-      const payload = isScheduleEvent
-        ? undefined
-        : (context.payload as IssueCommentEvent | PullRequestReviewCommentEvent)
+      const payload = isCommentEvent
+        ? (context.payload as IssueCommentEvent | PullRequestReviewCommentEvent)
+        : undefined
       const issueEvent = payload && isIssueCommentEvent(payload) ? payload : undefined
       const actor = isScheduleEvent ? undefined : context.actor
 
       const issueId = isScheduleEvent
         ? undefined
-        : context.eventName === "pull_request_review_comment"
-          ? (payload as PullRequestReviewCommentEvent).pull_request.number
-          : (payload as IssueCommentEvent).issue.number
+        : context.eventName === "issue_comment"
+          ? (payload as IssueCommentEvent).issue.number
+          : (payload as PullRequestEvent | PullRequestReviewCommentEvent).pull_request.number
       const runUrl = `/${owner}/${repo}/actions/runs/${runId}`
       const shareBaseUrl = isMock ? "https://dev.opencode.ai" : "https://opencode.ai"
 
@@ -424,11 +425,11 @@ export const GithubRunCommand = cmd({
       type PromptFiles = Awaited<ReturnType<typeof getUserPrompt>>["promptFiles"]
       const triggerCommentId = payload?.comment.id
       const useGithubToken = normalizeUseGithubToken()
-      const commentType = isScheduleEvent
-        ? undefined
-        : context.eventName === "pull_request_review_comment"
+      const commentType = isCommentEvent
+        ? context.eventName === "pull_request_review_comment"
           ? "pr_review"
           : "issue"
+        : undefined
 
       try {
         if (useGithubToken) {
@@ -455,7 +456,7 @@ export const GithubRunCommand = cmd({
         // Skip permission check for schedule events (no actor to check)
         if (!isScheduleEvent) {
           await assertPermissions()
-          await addReaction(commentType!)
+          await addReaction(commentType)
         }
 
         // Setup opencode session
@@ -494,7 +495,10 @@ export const GithubRunCommand = cmd({
           } else {
             console.log("Response:", response)
           }
-        } else if (context.eventName === "pull_request_review_comment" || issueEvent?.issue.pull_request) {
+        } else if (
+          ["pull_request", "pull_request_review_comment"].includes(context.eventName) ||
+          issueEvent?.issue.pull_request
+        ) {
           const prData = await fetchPR()
           // Local PR
           if (prData.headRepository.nameWithOwner === prData.baseRepository.nameWithOwner) {
@@ -509,7 +513,7 @@ export const GithubRunCommand = cmd({
             }
             const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`))
             await createComment(`${response}${footer({ image: !hasShared })}`)
-            await removeReaction(commentType!)
+            await removeReaction(commentType)
           }
           // Fork PR
           else {
@@ -524,7 +528,7 @@ export const GithubRunCommand = cmd({
             }
             const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`))
             await createComment(`${response}${footer({ image: !hasShared })}`)
-            await removeReaction(commentType!)
+            await removeReaction(commentType)
           }
         }
         // Issue
@@ -545,10 +549,10 @@ export const GithubRunCommand = cmd({
               `${response}\n\nCloses #${issueId}${footer({ image: true })}`,
             )
             await createComment(`Created PR #${pr}${footer({ image: true })}`)
-            await removeReaction(commentType!)
+            await removeReaction(commentType)
           } else {
             await createComment(`${response}${footer({ image: true })}`)
-            await removeReaction(commentType!)
+            await removeReaction(commentType)
           }
         }
       } catch (e: any) {
@@ -562,7 +566,7 @@ export const GithubRunCommand = cmd({
         }
         if (!isScheduleEvent) {
           await createComment(`${msg}${footer()}`)
-          await removeReaction(commentType!)
+          await removeReaction(commentType)
         }
         core.setFailed(msg)
         // Also output the clean error message for the action to capture
@@ -657,6 +661,9 @@ export const GithubRunCommand = cmd({
           .map((m) => m.trim().toLowerCase())
           .filter(Boolean)
         let prompt = (() => {
+          if (!isCommentEvent) {
+            return "Review this pull request"
+          }
           const body = payload!.comment.body.trim()
           const bodyLower = body.toLowerCase()
           if (mentions.some((m) => bodyLower === m)) {
@@ -1030,30 +1037,57 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
         if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
       }
 
-      async function addReaction(commentType: "issue" | "pr_review") {
+      async function addReaction(commentType?: "issue" | "pr_review") {
         // Only called for non-schedule events, so triggerCommentId is defined
         console.log("Adding reaction...")
-        if (commentType === "pr_review") {
-          return await octoRest.rest.reactions.createForPullRequestReviewComment({
+        if (triggerCommentId) {
+          if (commentType === "pr_review") {
+            return await octoRest.rest.reactions.createForPullRequestReviewComment({
+              owner,
+              repo,
+              comment_id: triggerCommentId!,
+              content: AGENT_REACTION,
+            })
+          }
+          return await octoRest.rest.reactions.createForIssueComment({
             owner,
             repo,
             comment_id: triggerCommentId!,
             content: AGENT_REACTION,
           })
         }
-        return await octoRest.rest.reactions.createForIssueComment({
+        return await octoRest.rest.reactions.createForIssue({
           owner,
           repo,
-          comment_id: triggerCommentId!,
+          issue_number: issueId!,
           content: AGENT_REACTION,
         })
       }
 
-      async function removeReaction(commentType: "issue" | "pr_review") {
+      async function removeReaction(commentType?: "issue" | "pr_review") {
         // Only called for non-schedule events, so triggerCommentId is defined
         console.log("Removing reaction...")
-        if (commentType === "pr_review") {
-          const reactions = await octoRest.rest.reactions.listForPullRequestReviewComment({
+        if (triggerCommentId) {
+          if (commentType === "pr_review") {
+            const reactions = await octoRest.rest.reactions.listForPullRequestReviewComment({
+              owner,
+              repo,
+              comment_id: triggerCommentId!,
+              content: AGENT_REACTION,
+            })
+
+            const eyesReaction = reactions.data.find((r) => r.user?.login === AGENT_USERNAME)
+            if (!eyesReaction) return
+
+            return await octoRest.rest.reactions.deleteForPullRequestComment({
+              owner,
+              repo,
+              comment_id: triggerCommentId!,
+              reaction_id: eyesReaction.id,
+            })
+          }
+
+          const reactions = await octoRest.rest.reactions.listForIssueComment({
             owner,
             repo,
             comment_id: triggerCommentId!,
@@ -1063,29 +1097,28 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
           const eyesReaction = reactions.data.find((r) => r.user?.login === AGENT_USERNAME)
           if (!eyesReaction) return
 
-          await octoRest.rest.reactions.deleteForPullRequestComment({
+          return await octoRest.rest.reactions.deleteForIssueComment({
             owner,
             repo,
             comment_id: triggerCommentId!,
             reaction_id: eyesReaction.id,
           })
-          return
         }
 
-        const reactions = await octoRest.rest.reactions.listForIssueComment({
+        const reactions = await octoRest.rest.reactions.listForIssue({
           owner,
           repo,
-          comment_id: triggerCommentId!,
+          issue_number: issueId!,
           content: AGENT_REACTION,
         })
 
         const eyesReaction = reactions.data.find((r) => r.user?.login === AGENT_USERNAME)
         if (!eyesReaction) return
 
-        await octoRest.rest.reactions.deleteForIssueComment({
+        await octoRest.rest.reactions.deleteForIssue({
           owner,
           repo,
-          comment_id: triggerCommentId!,
+          issue_number: issueId!,
           reaction_id: eyesReaction.id,
         })
       }
@@ -1178,7 +1211,7 @@ query($owner: String!, $repo: String!, $number: Int!) {
         const comments = (issue.comments?.nodes || [])
           .filter((c) => {
             const id = parseInt(c.databaseId)
-            return id !== payload!.comment.id
+            return id !== triggerCommentId
           })
           .map((c) => `  - ${c.author.login} at ${c.createdAt}: ${c.body}`)
 
@@ -1306,7 +1339,7 @@ query($owner: String!, $repo: String!, $number: Int!) {
         const comments = (pr.comments?.nodes || [])
           .filter((c) => {
             const id = parseInt(c.databaseId)
-            return id !== payload!.comment.id
+            return id !== triggerCommentId
           })
           .map((c) => `- ${c.author.login} at ${c.createdAt}: ${c.body}`)
 

+ 17 - 0
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

@@ -731,6 +731,23 @@ export function Prompt(props: PromptProps) {
                   e.preventDefault()
                   return
                 }
+                // Handle clipboard paste (Ctrl+V) - check for images first on Windows
+                // This is needed because Windows terminal doesn't properly send image data
+                // through bracketed paste, so we need to intercept the keypress and
+                // directly read from clipboard before the terminal handles it
+                if (keybind.match("input_paste", e)) {
+                  const content = await Clipboard.read()
+                  if (content?.mime.startsWith("image/")) {
+                    e.preventDefault()
+                    await pasteImage({
+                      filename: "clipboard",
+                      mime: content.mime,
+                      content: content.data,
+                    })
+                    return
+                  }
+                  // If no image, let the default paste behavior continue
+                }
                 if (keybind.match("input_clear", e) && store.prompt.input !== "") {
                   input.clear()
                   input.extmarks.clear()

+ 1 - 1
packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx

@@ -54,7 +54,7 @@ export function DialogMessage(props: {
         {
           title: "Copy",
           value: "message.copy",
-          description: "copy message text to clipboard",
+          description: "message text to clipboard",
           onSelect: async (dialog) => {
             const msg = message()
             if (!msg) return

+ 1 - 1
packages/opencode/src/cli/cmd/tui/routes/session/dialog-subagent.tsx

@@ -11,7 +11,7 @@ export function DialogSubagent(props: { sessionID: string }) {
         {
           title: "Open",
           value: "subagent.view",
-          description: "open the subagent's session",
+          description: "the subagent's session",
           onSelect: (dialog) => {
             route.navigate({
               type: "session",

+ 3 - 0
packages/opencode/src/cli/cmd/tui/routes/session/header.tsx

@@ -81,6 +81,9 @@ export function Header() {
               <text fg={theme.text}>
                 <b>Subagent session</b>
               </text>
+              <text fg={theme.text}>
+                Parent <span style={{ fg: theme.textMuted }}>{keybind.print("session_parent")}</span>
+              </text>
               <text fg={theme.text}>
                 Prev <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle_reverse")}</span>
               </text>

+ 79 - 0
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

@@ -201,6 +201,52 @@ export function Session() {
   let prompt: PromptRef
   const keybind = useKeybind()
 
+  // Helper: Find next visible message boundary in direction
+  const findNextVisibleMessage = (direction: "next" | "prev"): string | null => {
+    const children = scroll.getChildren()
+    const messagesList = messages()
+    const scrollTop = scroll.y
+
+    // Get visible messages sorted by position, filtering for valid non-synthetic, non-ignored content
+    const visibleMessages = children
+      .filter((c) => {
+        if (!c.id) return false
+        const message = messagesList.find((m) => m.id === c.id)
+        if (!message) return false
+
+        // Check if message has valid non-synthetic, non-ignored text parts
+        const parts = sync.data.part[message.id]
+        if (!parts || !Array.isArray(parts)) return false
+
+        return parts.some((part) => part && part.type === "text" && !part.synthetic && !part.ignored)
+      })
+      .sort((a, b) => a.y - b.y)
+
+    if (visibleMessages.length === 0) return null
+
+    if (direction === "next") {
+      // Find first message below current position
+      return visibleMessages.find((c) => c.y > scrollTop + 10)?.id ?? null
+    }
+    // Find last message above current position
+    return [...visibleMessages].reverse().find((c) => c.y < scrollTop - 10)?.id ?? null
+  }
+
+  // Helper: Scroll to message in direction or fallback to page scroll
+  const scrollToMessage = (direction: "next" | "prev", dialog: ReturnType<typeof useDialog>) => {
+    const targetID = findNextVisibleMessage(direction)
+
+    if (!targetID) {
+      scroll.scrollBy(direction === "next" ? scroll.height : -scroll.height)
+      dialog.clear()
+      return
+    }
+
+    const child = scroll.getChildren().find((c) => c.id === targetID)
+    if (child) scroll.scrollBy(child.y - scroll.y - 1)
+    dialog.clear()
+  }
+
   useKeyboard((evt) => {
     if (dialog.stack.length > 0) return
 
@@ -634,6 +680,22 @@ export function Session() {
         }
       },
     },
+    {
+      title: "Next message",
+      value: "session.message.next",
+      keybind: "messages_next",
+      category: "Session",
+      disabled: true,
+      onSelect: (dialog) => scrollToMessage("next", dialog),
+    },
+    {
+      title: "Previous message",
+      value: "session.message.previous",
+      keybind: "messages_previous",
+      category: "Session",
+      disabled: true,
+      onSelect: (dialog) => scrollToMessage("prev", dialog),
+    },
     {
       title: "Copy last assistant message",
       value: "messages.copy",
@@ -808,6 +870,23 @@ export function Session() {
         dialog.clear()
       },
     },
+    {
+      title: "Go to parent session",
+      value: "session.parent",
+      keybind: "session_parent",
+      category: "Session",
+      disabled: true,
+      onSelect: (dialog) => {
+        const parentID = session()?.parentID
+        if (parentID) {
+          navigate({
+            type: "session",
+            sessionID: parentID,
+          })
+        }
+        dialog.clear()
+      },
+    },
   ])
 
   const revertInfo = createMemo(() => session()?.revert)

+ 31 - 7
packages/opencode/src/command/template/review.txt

@@ -28,31 +28,53 @@ Use best judgement when processing input.
 
 ---
 
+## Gathering Context
+
+**Diffs alone are not enough.** After getting the diff, read the entire file(s) being modified to understand the full context. Code that looks wrong in isolation may be correct given surrounding logic—and vice versa.
+
+- Use the diff to identify which files changed
+- Read the full file to understand existing patterns, control flow, and error handling
+- Check for existing style guide or conventions files (CONVENTIONS.md, AGENTS.md, .editorconfig, etc.)
+
+---
+
 ## What to Look For
 
 **Bugs** - Your primary focus.
 - Logic errors, off-by-one mistakes, incorrect conditionals
-- Edge cases: null/empty inputs, error conditions, race conditions
+- If-else guards: missing guards, incorrect branching, unreachable code paths
+- Edge cases: null/empty/undefined inputs, error conditions, race conditions
 - Security issues: injection, auth bypass, data exposure
-- Broken error handling that swallows failures
+- Broken error handling that swallows failures, throws unexpectedly or returns error types that are not caught.
 
 **Structure** - Does the code fit the codebase?
 - Does it follow existing patterns and conventions?
 - Are there established abstractions it should use but doesn't?
+- Excessive nesting that could be flattened with early returns or extraction
 
 **Performance** - Only flag if obviously problematic.
 - O(n²) on unbounded data, N+1 queries, blocking I/O on hot paths
 
+---
+
 ## Before You Flag Something
 
-Be certain. If you're going to call something a bug, you need to be confident it actually is one.
+**Be certain.** If you're going to call something a bug, you need to be confident it actually is one.
 
 - Only review the changes - do not review pre-existing code that wasn't modified
 - Don't flag something as a bug if you're unsure - investigate first
-- Don't flag style preferences as issues
 - Don't invent hypothetical problems - if an edge case matters, explain the realistic scenario where it breaks
 - If you need more context to be sure, use the tools below to get it
 
+**Don't be a zealot about style.** When checking code against conventions:
+
+- Verify the code is *actually* in violation. Don't complain about else statements if early returns are already being used correctly.
+- Some "violations" are acceptable when they're the simplest option. A `let` statement is fine if the alternative is convoluted.
+- Excessive nesting is a legitimate concern regardless of other style choices.
+- Don't flag style preferences as issues unless they clearly violate established project conventions.
+
+---
+
 ## Tools
 
 Use these to inform your review:
@@ -63,11 +85,13 @@ Use these to inform your review:
 
 If you're uncertain about something and can't verify it with these tools, say "I'm not sure about X" rather than flagging it as a definite issue.
 
-## Tone and Approach
+---
+
+## Output
 
 1. If there is a bug, be direct and clear about why it is a bug.
-2. You should clearly communicate severity of issues, do not claim issues are more severe than they actually are.
+2. Clearly communicate severity of issues. Do not overstate severity.
 3. Critiques should clearly and explicitly communicate the scenarios, environments, or inputs that are necessary for the bug to arise. The comment should immediately indicate that the issue's severity depends on these factors.
 4. Your tone should be matter-of-fact and not accusatory or overly positive. It should read as a helpful AI assistant suggestion without sounding too much like a human reviewer.
-5. Write in a manner that allows reader to quickly understand issue without reading too closely.
+5. Write so the reader can quickly understand the issue without reading too closely.
 6. AVOID flattery, do not give any comments that are not helpful to the reader. Avoid phrasing like "Great job ...", "Thanks for ...".

+ 3 - 0
packages/opencode/src/config/config.ts

@@ -457,6 +457,8 @@ export namespace Config {
         .describe("Scroll messages down by half page"),
       messages_first: z.string().optional().default("ctrl+g,home").describe("Navigate to first message"),
       messages_last: z.string().optional().default("ctrl+alt+g,end").describe("Navigate to last message"),
+      messages_next: z.string().optional().default("none").describe("Navigate to next message"),
+      messages_previous: z.string().optional().default("none").describe("Navigate to previous message"),
       messages_last_user: z.string().optional().default("none").describe("Navigate to last user message"),
       messages_copy: z.string().optional().default("<leader>y").describe("Copy message"),
       messages_undo: z.string().optional().default("<leader>u").describe("Undo message"),
@@ -561,6 +563,7 @@ export namespace Config {
       history_next: z.string().optional().default("down").describe("Next history item"),
       session_child_cycle: z.string().optional().default("<leader>right").describe("Next child session"),
       session_child_cycle_reverse: z.string().optional().default("<leader>left").describe("Previous child session"),
+      session_parent: z.string().optional().default("<leader>up").describe("Go to parent session"),
       terminal_suspend: z.string().optional().default("ctrl+z").describe("Suspend terminal"),
       terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"),
     })

+ 1 - 0
packages/opencode/src/flag/flag.ts

@@ -30,6 +30,7 @@ export namespace Flag {
   export const OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX = number("OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX")
   export const OPENCODE_EXPERIMENTAL_OXFMT = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_OXFMT")
   export const OPENCODE_EXPERIMENTAL_LSP_TY = truthy("OPENCODE_EXPERIMENTAL_LSP_TY")
+  export const OPENCODE_EXPERIMENTAL_LSP_TOOL = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_LSP_TOOL")
 
   function truthy(key: string) {
     const value = process.env[key]?.toLowerCase()

+ 7 - 8
packages/opencode/src/installation/index.ts

@@ -1,5 +1,4 @@
 import { BusEvent } from "@/bus/bus-event"
-import { Bus } from "@/bus"
 import path from "path"
 import { $ } from "bun"
 import z from "zod"
@@ -66,23 +65,23 @@ export namespace Installation {
     const checks = [
       {
         name: "npm" as const,
-        command: () => $`npm list -g --depth=0`.throws(false).text(),
+        command: () => $`npm list -g --depth=0`.throws(false).quiet().text(),
       },
       {
         name: "yarn" as const,
-        command: () => $`yarn global list`.throws(false).text(),
+        command: () => $`yarn global list`.throws(false).quiet().text(),
       },
       {
         name: "pnpm" as const,
-        command: () => $`pnpm list -g --depth=0`.throws(false).text(),
+        command: () => $`pnpm list -g --depth=0`.throws(false).quiet().text(),
       },
       {
         name: "bun" as const,
-        command: () => $`bun pm ls -g`.throws(false).text(),
+        command: () => $`bun pm ls -g`.throws(false).quiet().text(),
       },
       {
         name: "brew" as const,
-        command: () => $`brew list --formula opencode`.throws(false).text(),
+        command: () => $`brew list --formula opencode`.throws(false).quiet().text(),
       },
     ]
 
@@ -112,9 +111,9 @@ export namespace Installation {
   )
 
   async function getBrewFormula() {
-    const tapFormula = await $`brew list --formula sst/tap/opencode`.throws(false).text()
+    const tapFormula = await $`brew list --formula sst/tap/opencode`.throws(false).quiet().text()
     if (tapFormula.includes("opencode")) return "sst/tap/opencode"
-    const coreFormula = await $`brew list --formula opencode`.throws(false).text()
+    const coreFormula = await $`brew list --formula opencode`.throws(false).quiet().text()
     if (coreFormula.includes("opencode")) return "opencode"
     return "opencode"
   }

+ 114 - 21
packages/opencode/src/lsp/index.ts

@@ -261,23 +261,36 @@ export namespace LSP {
     return result
   }
 
+  export async function hasClients(file: string) {
+    const s = await state()
+    const extension = path.parse(file).ext || file
+    for (const server of Object.values(s.servers)) {
+      if (server.extensions.length && !server.extensions.includes(extension)) continue
+      const root = await server.root(file)
+      if (!root) continue
+      if (s.broken.has(root + server.id)) continue
+      return true
+    }
+    return false
+  }
+
   export async function touchFile(input: string, waitForDiagnostics?: boolean) {
     log.info("touching file", { file: input })
     const clients = await getClients(input)
-    await run(async (client) => {
-      if (!clients.includes(client)) return
-      const wait = waitForDiagnostics ? client.waitForDiagnostics({ path: input }) : Promise.resolve()
-      await client.notify.open({ path: input })
-
-      return wait
-    }).catch((err) => {
+    await Promise.all(
+      clients.map(async (client) => {
+        const wait = waitForDiagnostics ? client.waitForDiagnostics({ path: input }) : Promise.resolve()
+        await client.notify.open({ path: input })
+        return wait
+      }),
+    ).catch((err) => {
       log.error("failed to touch file", { err, file: input })
     })
   }
 
   export async function diagnostics() {
     const results: Record<string, LSPClient.Diagnostic[]> = {}
-    for (const result of await run(async (client) => client.diagnostics)) {
+    for (const result of await runAll(async (client) => client.diagnostics)) {
       for (const [path, diagnostics] of result.entries()) {
         const arr = results[path] || []
         arr.push(...diagnostics)
@@ -288,16 +301,18 @@ export namespace LSP {
   }
 
   export async function hover(input: { file: string; line: number; character: number }) {
-    return run((client) => {
-      return client.connection.sendRequest("textDocument/hover", {
-        textDocument: {
-          uri: pathToFileURL(input.file).href,
-        },
-        position: {
-          line: input.line,
-          character: input.character,
-        },
-      })
+    return run(input.file, (client) => {
+      return client.connection
+        .sendRequest("textDocument/hover", {
+          textDocument: {
+            uri: pathToFileURL(input.file).href,
+          },
+          position: {
+            line: input.line,
+            character: input.character,
+          },
+        })
+        .catch(() => null)
     })
   }
 
@@ -342,7 +357,7 @@ export namespace LSP {
   ]
 
   export async function workspaceSymbol(query: string) {
-    return run((client) =>
+    return runAll((client) =>
       client.connection
         .sendRequest("workspace/symbol", {
           query,
@@ -354,7 +369,8 @@ export namespace LSP {
   }
 
   export async function documentSymbol(uri: string) {
-    return run((client) =>
+    const file = new URL(uri).pathname
+    return run(file, (client) =>
       client.connection
         .sendRequest("textDocument/documentSymbol", {
           textDocument: {
@@ -367,12 +383,89 @@ export namespace LSP {
       .then((result) => result.filter(Boolean))
   }
 
-  async function run<T>(input: (client: LSPClient.Info) => Promise<T>): Promise<T[]> {
+  export async function definition(input: { file: string; line: number; character: number }) {
+    return run(input.file, (client) =>
+      client.connection
+        .sendRequest("textDocument/definition", {
+          textDocument: { uri: pathToFileURL(input.file).href },
+          position: { line: input.line, character: input.character },
+        })
+        .catch(() => null),
+    ).then((result) => result.flat().filter(Boolean))
+  }
+
+  export async function references(input: { file: string; line: number; character: number }) {
+    return run(input.file, (client) =>
+      client.connection
+        .sendRequest("textDocument/references", {
+          textDocument: { uri: pathToFileURL(input.file).href },
+          position: { line: input.line, character: input.character },
+          context: { includeDeclaration: true },
+        })
+        .catch(() => []),
+    ).then((result) => result.flat().filter(Boolean))
+  }
+
+  export async function implementation(input: { file: string; line: number; character: number }) {
+    return run(input.file, (client) =>
+      client.connection
+        .sendRequest("textDocument/implementation", {
+          textDocument: { uri: pathToFileURL(input.file).href },
+          position: { line: input.line, character: input.character },
+        })
+        .catch(() => null),
+    ).then((result) => result.flat().filter(Boolean))
+  }
+
+  export async function prepareCallHierarchy(input: { file: string; line: number; character: number }) {
+    return run(input.file, (client) =>
+      client.connection
+        .sendRequest("textDocument/prepareCallHierarchy", {
+          textDocument: { uri: pathToFileURL(input.file).href },
+          position: { line: input.line, character: input.character },
+        })
+        .catch(() => []),
+    ).then((result) => result.flat().filter(Boolean))
+  }
+
+  export async function incomingCalls(input: { file: string; line: number; character: number }) {
+    return run(input.file, async (client) => {
+      const items = (await client.connection
+        .sendRequest("textDocument/prepareCallHierarchy", {
+          textDocument: { uri: pathToFileURL(input.file).href },
+          position: { line: input.line, character: input.character },
+        })
+        .catch(() => [])) as any[]
+      if (!items?.length) return []
+      return client.connection.sendRequest("callHierarchy/incomingCalls", { item: items[0] }).catch(() => [])
+    }).then((result) => result.flat().filter(Boolean))
+  }
+
+  export async function outgoingCalls(input: { file: string; line: number; character: number }) {
+    return run(input.file, async (client) => {
+      const items = (await client.connection
+        .sendRequest("textDocument/prepareCallHierarchy", {
+          textDocument: { uri: pathToFileURL(input.file).href },
+          position: { line: input.line, character: input.character },
+        })
+        .catch(() => [])) as any[]
+      if (!items?.length) return []
+      return client.connection.sendRequest("callHierarchy/outgoingCalls", { item: items[0] }).catch(() => [])
+    }).then((result) => result.flat().filter(Boolean))
+  }
+
+  async function runAll<T>(input: (client: LSPClient.Info) => Promise<T>): Promise<T[]> {
     const clients = await state().then((x) => x.clients)
     const tasks = clients.map((x) => input(x))
     return Promise.all(tasks)
   }
 
+  async function run<T>(file: string, input: (client: LSPClient.Info) => Promise<T>): Promise<T[]> {
+    const clients = await getClients(file)
+    const tasks = clients.map((x) => input(x))
+    return Promise.all(tasks)
+  }
+
   export namespace Diagnostic {
     export function pretty(diagnostic: LSPClient.Diagnostic) {
       const severityMap = {

+ 3 - 0
packages/opencode/src/lsp/language.ts

@@ -110,4 +110,7 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = {
   ".tf": "terraform",
   ".tfvars": "terraform-vars",
   ".hcl": "hcl",
+  ".nix": "nix",
+  ".typ": "typst",
+  ".typc": "typst",
 } as const

+ 146 - 0
packages/opencode/src/lsp/server.ts

@@ -1746,4 +1746,150 @@ export namespace LSPServer {
       }
     },
   }
+
+  export const Clojure: Info = {
+    id: "clojure-lsp",
+    extensions: [".clj", ".cljs", ".cljc", ".edn"],
+    root: NearestRoot(["deps.edn", "project.clj", "shadow-cljs.edn", "bb.edn", "build.boot"]),
+    async spawn(root) {
+      let bin = Bun.which("clojure-lsp")
+      if (!bin && process.platform === "win32") {
+        bin = Bun.which("clojure-lsp.exe")
+      }
+      if (!bin) {
+        log.info("clojure-lsp not found, please install clojure-lsp first")
+        return
+      }
+      return {
+        process: spawn(bin, ["listen"], {
+          cwd: root,
+        }),
+      }
+    },
+  }
+
+  export const Nixd: Info = {
+    id: "nixd",
+    extensions: [".nix"],
+    root: async (file) => {
+      // First, look for flake.nix - the most reliable Nix project root indicator
+      const flakeRoot = await NearestRoot(["flake.nix"])(file)
+      if (flakeRoot && flakeRoot !== Instance.directory) return flakeRoot
+
+      // If no flake.nix, fall back to git repository root
+      if (Instance.worktree && Instance.worktree !== Instance.directory) return Instance.worktree
+
+      // Finally, use the instance directory as fallback
+      return Instance.directory
+    },
+    async spawn(root) {
+      const nixd = Bun.which("nixd")
+      if (!nixd) {
+        log.info("nixd not found, please install nixd first")
+        return
+      }
+      return {
+        process: spawn(nixd, [], {
+          cwd: root,
+          env: {
+            ...process.env,
+          },
+        }),
+      }
+    },
+  }
+
+  export const Tinymist: Info = {
+    id: "tinymist",
+    extensions: [".typ", ".typc"],
+    root: NearestRoot(["typst.toml"]),
+    async spawn(root) {
+      let bin = Bun.which("tinymist", {
+        PATH: process.env["PATH"] + path.delimiter + Global.Path.bin,
+      })
+
+      if (!bin) {
+        if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
+        log.info("downloading tinymist from GitHub releases")
+
+        const response = await fetch("https://api.github.com/repos/Myriad-Dreamin/tinymist/releases/latest")
+        if (!response.ok) {
+          log.error("Failed to fetch tinymist release info")
+          return
+        }
+
+        const release = (await response.json()) as {
+          tag_name?: string
+          assets?: { name?: string; browser_download_url?: string }[]
+        }
+
+        const platform = process.platform
+        const arch = process.arch
+
+        const tinymistArch = arch === "arm64" ? "aarch64" : "x86_64"
+        let tinymistPlatform: string
+        let ext: string
+
+        if (platform === "darwin") {
+          tinymistPlatform = "apple-darwin"
+          ext = "tar.gz"
+        } else if (platform === "win32") {
+          tinymistPlatform = "pc-windows-msvc"
+          ext = "zip"
+        } else {
+          tinymistPlatform = "unknown-linux-gnu"
+          ext = "tar.gz"
+        }
+
+        const assetName = `tinymist-${tinymistArch}-${tinymistPlatform}.${ext}`
+
+        const assets = release.assets ?? []
+        const asset = assets.find((a) => a.name === assetName)
+        if (!asset?.browser_download_url) {
+          log.error(`Could not find asset ${assetName} in tinymist release`)
+          return
+        }
+
+        const downloadResponse = await fetch(asset.browser_download_url)
+        if (!downloadResponse.ok) {
+          log.error("Failed to download tinymist")
+          return
+        }
+
+        const tempPath = path.join(Global.Path.bin, assetName)
+        await Bun.file(tempPath).write(downloadResponse)
+
+        if (ext === "zip") {
+          const ok = await Archive.extractZip(tempPath, Global.Path.bin)
+            .then(() => true)
+            .catch((error) => {
+              log.error("Failed to extract tinymist archive", { error })
+              return false
+            })
+          if (!ok) return
+        } else {
+          await $`tar -xzf ${tempPath} --strip-components=1`.cwd(Global.Path.bin).quiet().nothrow()
+        }
+
+        await fs.rm(tempPath, { force: true })
+
+        bin = path.join(Global.Path.bin, "tinymist" + (platform === "win32" ? ".exe" : ""))
+
+        if (!(await Bun.file(bin).exists())) {
+          log.error("Failed to extract tinymist binary")
+          return
+        }
+
+        if (platform !== "win32") {
+          await $`chmod +x ${bin}`.quiet().nothrow()
+        }
+
+        log.info("installed tinymist", { bin })
+      }
+
+      return {
+        process: spawn(bin, { cwd: root }),
+      }
+    },
+  }
 }

+ 20 - 0
packages/opencode/src/provider/provider.ts

@@ -25,6 +25,15 @@ import { createOpenAI } from "@ai-sdk/openai"
 import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
 import { createOpenRouter, type LanguageModelV2 } from "@openrouter/ai-sdk-provider"
 import { createOpenaiCompatible as createGitHubCopilotOpenAICompatible } from "./sdk/openai-compatible/src"
+import { createXai } from "@ai-sdk/xai"
+import { createMistral } from "@ai-sdk/mistral"
+import { createGroq } from "@ai-sdk/groq"
+import { createDeepInfra } from "@ai-sdk/deepinfra"
+import { createCerebras } from "@ai-sdk/cerebras"
+import { createCohere } from "@ai-sdk/cohere"
+import { createGateway } from "@ai-sdk/gateway"
+import { createTogetherAI } from "@ai-sdk/togetherai"
+import { createPerplexity } from "@ai-sdk/perplexity"
 
 export namespace Provider {
   const log = Log.create({ service: "provider" })
@@ -39,6 +48,15 @@ export namespace Provider {
     "@ai-sdk/openai": createOpenAI,
     "@ai-sdk/openai-compatible": createOpenAICompatible,
     "@openrouter/ai-sdk-provider": createOpenRouter,
+    "@ai-sdk/xai": createXai,
+    "@ai-sdk/mistral": createMistral,
+    "@ai-sdk/groq": createGroq,
+    "@ai-sdk/deepinfra": createDeepInfra,
+    "@ai-sdk/cerebras": createCerebras,
+    "@ai-sdk/cohere": createCohere,
+    "@ai-sdk/gateway": createGateway,
+    "@ai-sdk/togetherai": createTogetherAI,
+    "@ai-sdk/perplexity": createPerplexity,
     // @ts-ignore (TODO: kill this code so we dont have to maintain it)
     "@ai-sdk/github-copilot": createGitHubCopilotOpenAICompatible,
   }
@@ -67,6 +85,8 @@ export namespace Provider {
         const env = Env.all()
         if (input.env.some((item) => env[item])) return true
         if (await Auth.get(input.id)) return true
+        const config = await Config.get()
+        if (config.provider?.["opencode"]?.options?.apiKey) return true
         return false
       })()
 

+ 5 - 2
packages/opencode/src/provider/transform.ts

@@ -227,13 +227,16 @@ export namespace ProviderTransform {
   export function topP(model: Provider.Model) {
     const id = model.id.toLowerCase()
     if (id.includes("qwen")) return 1
-    if (id.includes("minimax-m2")) return 0.95
+    if (id.includes("minimax-m2")) {
+      if (id.includes("m2.1")) return 0.9
+      return 0.95
+    }
     return undefined
   }
 
   export function topK(model: Provider.Model) {
     const id = model.id.toLowerCase()
-    if (id.includes("minimax-m2")) return 40
+    if (id.includes("minimax-m2")) return 20
     return undefined
   }
 

+ 2 - 1
packages/opencode/src/server/server.ts

@@ -1054,6 +1054,7 @@ export namespace Server {
           z.object({
             providerID: z.string(),
             modelID: z.string(),
+            auto: z.boolean().optional().default(false),
           }),
         ),
         async (c) => {
@@ -1075,7 +1076,7 @@ export namespace Server {
               providerID: body.providerID,
               modelID: body.modelID,
             },
-            auto: false,
+            auto: body.auto,
           })
           await SessionPrompt.loop(sessionID)
           return c.json(true)

+ 14 - 0
packages/opencode/src/session/processor.ts

@@ -365,6 +365,20 @@ export namespace SessionProcessor {
               error: input.assistantMessage.error,
             })
           }
+          if (snapshot) {
+            const patch = await Snapshot.patch(snapshot)
+            if (patch.files.length) {
+              await Session.updatePart({
+                id: Identifier.ascending("part"),
+                messageID: input.assistantMessage.id,
+                sessionID: input.sessionID,
+                type: "patch",
+                hash: patch.hash,
+                files: patch.files,
+              })
+            }
+            snapshot = undefined
+          }
           const p = await MessageV2.parts(input.assistantMessage.id)
           for (const part of p) {
             if (part.type === "tool" && part.state.status !== "completed" && part.state.status !== "error") {

+ 15 - 15
packages/opencode/src/skill/skill.ts

@@ -59,7 +59,7 @@ export namespace Skill {
   )
 
   const SKILL_GLOB = new Bun.Glob("skill/**/SKILL.md")
-  const CLAUDE_SKILL_GLOB = new Bun.Glob("**/SKILL.md")
+  // const CLAUDE_SKILL_GLOB = new Bun.Glob("*/SKILL.md")
 
   interface DiscoveredSkill {
     path: string
@@ -85,20 +85,20 @@ export namespace Skill {
     }
 
     // Also scan .claude/skills/ walking up from cwd to worktree
-    for await (const dir of Filesystem.up({
-      targets: [".claude/skills"],
-      start: Instance.directory,
-      stop: Instance.worktree,
-    })) {
-      for await (const match of CLAUDE_SKILL_GLOB.scan({
-        cwd: dir,
-        absolute: true,
-        onlyFiles: true,
-        followSymlinks: true,
-      })) {
-        results.push({ path: match, baseDir: dir })
-      }
-    }
+    // for await (const dir of Filesystem.up({
+    //   targets: [".claude/skills"],
+    //   start: Instance.directory,
+    //   stop: Instance.worktree,
+    // })) {
+    //   for await (const match of CLAUDE_SKILL_GLOB.scan({
+    //     cwd: dir,
+    //     absolute: true,
+    //     onlyFiles: true,
+    //     followSymlinks: true,
+    //   })) {
+    //     paths.push(match)
+    //   }
+    // }
 
     return results
   }

+ 87 - 0
packages/opencode/src/tool/lsp.ts

@@ -0,0 +1,87 @@
+import z from "zod"
+import { Tool } from "./tool"
+import path from "path"
+import { LSP } from "../lsp"
+import DESCRIPTION from "./lsp.txt"
+import { Instance } from "../project/instance"
+import { pathToFileURL } from "url"
+
+const operations = [
+  "goToDefinition",
+  "findReferences",
+  "hover",
+  "documentSymbol",
+  "workspaceSymbol",
+  "goToImplementation",
+  "prepareCallHierarchy",
+  "incomingCalls",
+  "outgoingCalls",
+] as const
+
+export const LspTool = Tool.define("lsp", {
+  description: DESCRIPTION,
+  parameters: z.object({
+    operation: z.enum(operations).describe("The LSP operation to perform"),
+    filePath: z.string().describe("The absolute or relative path to the file"),
+    line: z.number().int().min(1).describe("The line number (1-based, as shown in editors)"),
+    character: z.number().int().min(1).describe("The character offset (1-based, as shown in editors)"),
+  }),
+  execute: async (args) => {
+    const file = path.isAbsolute(args.filePath) ? args.filePath : path.join(Instance.directory, args.filePath)
+    const uri = pathToFileURL(file).href
+    const position = {
+      file,
+      line: args.line - 1,
+      character: args.character - 1,
+    }
+
+    const relPath = path.relative(Instance.worktree, file)
+    const title = `${args.operation} ${relPath}:${args.line}:${args.character}`
+
+    const exists = await Bun.file(file).exists()
+    if (!exists) {
+      throw new Error(`File not found: ${file}`)
+    }
+
+    const available = await LSP.hasClients(file)
+    if (!available) {
+      throw new Error("No LSP server available for this file type.")
+    }
+
+    await LSP.touchFile(file, true)
+
+    const result: unknown[] = await (async () => {
+      switch (args.operation) {
+        case "goToDefinition":
+          return LSP.definition(position)
+        case "findReferences":
+          return LSP.references(position)
+        case "hover":
+          return LSP.hover(position)
+        case "documentSymbol":
+          return LSP.documentSymbol(uri)
+        case "workspaceSymbol":
+          return LSP.workspaceSymbol("")
+        case "goToImplementation":
+          return LSP.implementation(position)
+        case "prepareCallHierarchy":
+          return LSP.prepareCallHierarchy(position)
+        case "incomingCalls":
+          return LSP.incomingCalls(position)
+        case "outgoingCalls":
+          return LSP.outgoingCalls(position)
+      }
+    })()
+
+    const output = (() => {
+      if (result.length === 0) return `No results found for ${args.operation}`
+      return JSON.stringify(result, null, 2)
+    })()
+
+    return {
+      title,
+      metadata: { result },
+      output,
+    }
+  },
+})

+ 19 - 0
packages/opencode/src/tool/lsp.txt

@@ -0,0 +1,19 @@
+Interact with Language Server Protocol (LSP) servers to get code intelligence features.
+
+Supported operations:
+- goToDefinition: Find where a symbol is defined
+- findReferences: Find all references to a symbol
+- hover: Get hover information (documentation, type info) for a symbol
+- documentSymbol: Get all symbols (functions, classes, variables) in a document
+- workspaceSymbol: Search for symbols across the entire workspace
+- goToImplementation: Find implementations of an interface or abstract method
+- prepareCallHierarchy: Get call hierarchy item at a position (functions/methods)
+- incomingCalls: Find all functions/methods that call the function at a position
+- outgoingCalls: Find all functions/methods called by the function at a position
+
+All operations require:
+- filePath: The file to operate on
+- line: The line number (1-based, as shown in editors)
+- character: The character offset (1-based, as shown in editors)
+
+Note: LSP servers must be configured for the file type. If no server is available, an error will be returned.

+ 5 - 3
packages/opencode/src/tool/read.ts

@@ -60,10 +60,12 @@ export const ReadTool = Tool.define("read", {
     }
 
     const block = iife(() => {
-      const whitelist = [".env.sample", ".example"]
+      const basename = path.basename(filepath)
+      const whitelist = [".env.sample", ".env.example", ".example", ".env.template"]
 
-      if (whitelist.some((w) => filepath.endsWith(w))) return false
-      if (filepath.includes(".env")) return true
+      if (whitelist.some((w) => basename.endsWith(w))) return false
+      // Block .env, .env.local, .env.production, etc. but not .envrc
+      if (/^\.env(\.|$)/.test(basename)) return true
 
       return false
     })

+ 2 - 0
packages/opencode/src/tool/registry.ts

@@ -23,6 +23,7 @@ import { WebSearchTool } from "./websearch"
 import { CodeSearchTool } from "./codesearch"
 import { Flag } from "@/flag/flag"
 import { Log } from "@/util/log"
+import { LspTool } from "./lsp"
 
 export namespace ToolRegistry {
   const log = Log.create({ service: "tool.registry" })
@@ -104,6 +105,7 @@ export namespace ToolRegistry {
       WebSearchTool,
       CodeSearchTool,
       SkillTool,
+      ...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [LspTool] : []),
       ...(config.experimental?.batch_tool === true ? [BatchTool] : []),
       ...custom,
     ]

+ 26 - 26
packages/opencode/test/skill/skill.test.ts

@@ -261,31 +261,31 @@ description: An example skill for testing XML output.
   })
 })
 
-test("discovers skills from .claude/skills/ directory", async () => {
-  await using tmp = await tmpdir({
-    git: true,
-    init: async (dir) => {
-      const skillDir = path.join(dir, ".claude", "skills", "claude-skill")
-      await Bun.write(
-        path.join(skillDir, "SKILL.md"),
-        `---
-name: claude-skill
-description: A skill in the .claude/skills directory.
----
+// test("discovers skills from .claude/skills/ directory", async () => {
+//   await using tmp = await tmpdir({
+//     git: true,
+//     init: async (dir) => {
+//       const skillDir = path.join(dir, ".claude", "skills", "claude-skill")
+//       await Bun.write(
+//         path.join(skillDir, "SKILL.md"),
+//         `---
+// name: claude-skill
+// description: A skill in the .claude/skills directory.
+// ---
 
-# Claude Skill
-`,
-      )
-    },
-  })
+// # Claude Skill
+// `,
+//       )
+//     },
+//   })
 
-  await Instance.provide({
-    directory: tmp.path,
-    fn: async () => {
-      const skills = await Skill.all()
-      expect(skills.length).toBe(1)
-      expect(skills[0].name).toBe("claude-skill")
-      expect(skills[0].location).toContain(".claude/skills/claude-skill/SKILL.md")
-    },
-  })
-})
+//   await Instance.provide({
+//     directory: tmp.path,
+//     fn: async () => {
+//       const skills = await Skill.all()
+//       expect(skills.length).toBe(1)
+//       expect(skills[0].name).toBe("claude-skill")
+//       expect(skills[0].location).toContain(".claude/skills/claude-skill/SKILL.md")
+//     },
+//   })
+// })

+ 42 - 0
packages/opencode/test/tool/read.test.ts

@@ -0,0 +1,42 @@
+import { describe, expect, test } from "bun:test"
+import path from "path"
+import { ReadTool } from "../../src/tool/read"
+import { Instance } from "../../src/project/instance"
+import { tmpdir } from "../fixture/fixture"
+
+const ctx = {
+  sessionID: "test",
+  messageID: "",
+  callID: "",
+  agent: "build",
+  abort: AbortSignal.any([]),
+  metadata: () => {},
+}
+
+describe("tool.read env file blocking", () => {
+  test.each([
+    [".env", true],
+    [".env.local", true],
+    [".env.production", true],
+    [".env.sample", false],
+    [".env.example", false],
+    [".envrc", false],
+    ["environment.ts", false],
+  ])("%s blocked=%s", async (filename, blocked) => {
+    await using tmp = await tmpdir({
+      init: (dir) => Bun.write(path.join(dir, filename), "content"),
+    })
+    await Instance.provide({
+      directory: tmp.path,
+      fn: async () => {
+        const read = await ReadTool.init()
+        const promise = read.execute({ filePath: path.join(tmp.path, filename) }, ctx)
+        if (blocked) {
+          await expect(promise).rejects.toThrow("blocked")
+        } else {
+          expect((await promise).output).toContain("content")
+        }
+      },
+    })
+  })
+})

+ 1 - 1
packages/plugin/package.json

@@ -1,7 +1,7 @@
 {
   "$schema": "https://json.schemastore.org/package.json",
   "name": "@opencode-ai/plugin",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "type": "module",
   "scripts": {
     "typecheck": "tsgo --noEmit",

+ 1 - 1
packages/sdk/js/package.json

@@ -1,7 +1,7 @@
 {
   "$schema": "https://json.schemastore.org/package.json",
   "name": "@opencode-ai/sdk",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "type": "module",
   "scripts": {
     "typecheck": "tsgo --noEmit",

+ 8 - 0
packages/sdk/js/src/gen/types.gen.ts

@@ -858,6 +858,14 @@ export type KeybindsConfig = {
    * Navigate to last message
    */
   messages_last?: string
+  /**
+   * Navigate to next message
+   */
+  messages_next?: string
+  /**
+   * Navigate to previous message
+   */
+  messages_previous?: string
   /**
    * Navigate to last user message
    */

+ 2 - 0
packages/sdk/js/src/v2/gen/sdk.gen.ts

@@ -1132,6 +1132,7 @@ export class Session extends HeyApiClient {
       directory?: string
       providerID?: string
       modelID?: string
+      auto?: boolean
     },
     options?: Options<never, ThrowOnError>,
   ) {
@@ -1144,6 +1145,7 @@ export class Session extends HeyApiClient {
             { in: "query", key: "directory" },
             { in: "body", key: "providerID" },
             { in: "body", key: "modelID" },
+            { in: "body", key: "auto" },
           ],
         },
       ],

+ 13 - 0
packages/sdk/js/src/v2/gen/types.gen.ts

@@ -890,6 +890,14 @@ export type KeybindsConfig = {
    * Navigate to last message
    */
   messages_last?: string
+  /**
+   * Navigate to next message
+   */
+  messages_next?: string
+  /**
+   * Navigate to previous message
+   */
+  messages_previous?: string
   /**
    * Navigate to last user message
    */
@@ -1114,6 +1122,10 @@ export type KeybindsConfig = {
    * Previous child session
    */
   session_child_cycle_reverse?: string
+  /**
+   * Go to parent session
+   */
+  session_parent?: string
   /**
    * Suspend terminal
    */
@@ -2750,6 +2762,7 @@ export type SessionSummarizeData = {
   body?: {
     providerID: string
     modelID: string
+    auto?: boolean
   }
   path: {
     /**

+ 19 - 0
packages/sdk/openapi.json

@@ -1804,6 +1804,10 @@
                   },
                   "modelID": {
                     "type": "string"
+                  },
+                  "auto": {
+                    "default": false,
+                    "type": "boolean"
                   }
                 },
                 "required": ["providerID", "modelID"]
@@ -7304,6 +7308,16 @@
             "default": "ctrl+alt+g,end",
             "type": "string"
           },
+          "messages_next": {
+            "description": "Navigate to next message",
+            "default": "none",
+            "type": "string"
+          },
+          "messages_previous": {
+            "description": "Navigate to previous message",
+            "default": "none",
+            "type": "string"
+          },
           "messages_last_user": {
             "description": "Navigate to last user message",
             "default": "none",
@@ -7584,6 +7598,11 @@
             "default": "<leader>left",
             "type": "string"
           },
+          "session_parent": {
+            "description": "Go to parent session",
+            "default": "<leader>up",
+            "type": "string"
+          },
           "terminal_suspend": {
             "description": "Suspend terminal",
             "default": "ctrl+z",

+ 1 - 1
packages/slack/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/slack",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "type": "module",
   "scripts": {
     "dev": "bun run src/index.ts",

+ 1 - 1
packages/tauri/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@opencode-ai/tauri",
   "private": true,
-  "version": "1.0.185",
+  "version": "1.0.187",
   "type": "module",
   "scripts": {
     "typecheck": "tsgo -b",

+ 4 - 10
packages/tauri/scripts/prepare.ts

@@ -1,21 +1,15 @@
 #!/usr/bin/env bun
-
 import { $ } from "bun"
 
 import { copyBinaryToSidecarFolder, getCurrentSidecar } from "./utils"
-import { Script } from "@opencode-ai/script"
 
 const sidecarConfig = getCurrentSidecar()
 
 const dir = "src-tauri/target/opencode-binaries"
 
 await $`mkdir -p ${dir}`
-await $`gh release download v${Script.version} --pattern ${sidecarConfig.ocBinary}.${sidecarConfig.assetExt} --repo sst/opencode --skip-existing --dir ${dir}`
-
-if (sidecarConfig.assetExt === "tar.gz") {
-  await $`tar -xvzf ${dir}/${sidecarConfig.ocBinary}.${sidecarConfig.assetExt} -C ${dir}`
-} else {
-  await $`unzip -o ${dir}/${sidecarConfig.ocBinary}.${sidecarConfig.assetExt} -d ${dir}`
-}
+await $`gh run download ${Bun.env.GITHUB_RUN_ID} -n opencode-cli`.cwd(dir)
 
-await copyBinaryToSidecarFolder(`${dir}/opencode${process.platform === "win32" ? ".exe" : ""}`)
+await copyBinaryToSidecarFolder(
+  `${dir}/${sidecarConfig.ocBinary}/bin/opencode${process.platform === "win32" ? ".exe" : ""}`,
+)

+ 5 - 0
packages/tauri/scripts/utils.ts

@@ -21,6 +21,11 @@ export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; ass
     ocBinary: "opencode-linux-x64",
     assetExt: "tar.gz",
   },
+  {
+    rustTarget: "aarch64-unknown-linux-gnu",
+    ocBinary: "opencode-linux-arm64",
+    assetExt: "tar.gz",
+  },
 ]
 
 export const RUST_TARGET = Bun.env.RUST_TARGET

+ 1 - 1
packages/tauri/src-tauri/tauri.conf.json

@@ -26,7 +26,7 @@
       "icons/dev/icon.ico"
     ],
     "active": true,
-    "targets": ["deb", "rpm", "dmg", "nsis", "app"],
+    "targets": ["deb", "rpm", "dmg", "nsis", "app", "appimage"],
     "externalBin": ["sidecars/opencode-cli"],
     "macOS": {
       "entitlements": "./entitlements.plist"

+ 1 - 1
packages/ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode-ai/ui",
-  "version": "1.0.185",
+  "version": "1.0.187",
   "type": "module",
   "exports": {
     "./*": "./src/components/*.tsx",

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
packages/ui/src/assets/icons/provider/aihubmix.svg


+ 2 - 2
packages/ui/src/assets/icons/provider/alibaba-cn.svg

@@ -1,3 +1,3 @@
-<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
-  <path d="M24 14.014c-2.8 1.512-5.62 2.896-8.759 3.524-.7.139-1.476.139-2.187.043-.678-.085-1.017-.682-.776-1.31.23-.585.536-1.181.93-1.671.852-1.065 1.814-2.034 2.678-3.088a15.75 15.75 0 001.422-2.054c.306-.511.164-1.129-.372-1.384-.897-.437-1.859-.745-2.81-1.075-.11-.043-.274.074-.492.149.273.244.47.425.743.67-2.821.48-5.49 1.16-8.08 2.098-.012.053-.033.095-.023.117.383.585.208 1.032-.35 1.394a2.365 2.365 0 00-.568.522c1.706.5 3.226.213 4.68-.735-.087-.127-.175-.244-.262-.372.546.096.874.394.918.862.011.107-.054.213-.087.32-.077-.086-.175-.17-.24-.267-.045-.064-.056-.138-.088-.245-1.728 1.15-3.587 1.438-5.632.842 0 .404-.022.745.011 1.075.022.287-.098.415-.36.564-.591.362-1.204.735-1.696 1.214-.59.585-.371 1.299.427 1.597.907.34 1.859.35 2.81.234 1.126-.139 2.23-.32 3.456-.49-1.433.67-2.844 1.14-4.33 1.33-1.04.14-2.078.214-3.106-.084-1.476-.415-2.133-1.501-1.75-2.96.361-1.363 1.236-2.449 2.176-3.45 3.139-3.332 7.108-5.024 11.7-5.365 1.072-.074 2.155.064 3.16.511 1.411.639 2.002 1.99 1.313 3.354-.448.905-1.072 1.735-1.695 2.555-.612.809-1.301 1.554-1.946 2.331-.186.234-.361.48-.503.745-.274.5-.088.83.492.778 1.213-.118 2.45-.213 3.62-.511 1.716-.437 3.389-1.054 5.084-1.597.175-.043.339-.107.492-.17z"></path>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M38 23.021C33.8 25.289 29.5701 27.365 24.8616 28.307C23.8116 28.5154 22.6476 28.5154 21.5811 28.3715C20.5641 28.244 20.0557 27.3485 20.4172 26.4065C20.7621 25.529 21.2211 24.635 21.8121 23.9C23.0901 22.3025 24.5331 20.849 25.8291 19.268C26.6206 18.2991 27.3338 17.2689 27.9621 16.1871C28.4211 15.4206 28.2081 14.4936 27.4041 14.1111C26.0586 13.4556 24.6156 12.9936 23.1891 12.4986C23.0241 12.4341 22.7781 12.6096 22.4511 12.7221C22.8606 13.0881 23.1561 13.3596 23.5656 13.7271C19.3342 14.4471 15.3307 15.4671 11.4457 16.8741C11.4277 16.9536 11.3962 17.0166 11.4112 17.0496C11.9857 17.927 11.7232 18.5975 10.8862 19.1405C10.5613 19.3531 10.2735 19.6177 10.0342 19.9235C12.5932 20.6735 14.8732 20.243 17.0542 18.821C16.9237 18.6305 16.7917 18.455 16.6612 18.263C17.4802 18.407 17.9722 18.854 18.0382 19.556C18.0547 19.7165 17.9572 19.8755 17.9077 20.036C17.7922 19.907 17.6452 19.781 17.5477 19.6355C17.4802 19.5395 17.4637 19.4285 17.4157 19.268C14.8237 20.993 12.0352 21.425 8.96775 20.531C8.96775 21.137 8.93475 21.6485 8.98425 22.1435C9.01725 22.574 8.83725 22.766 8.44426 22.9895C7.55776 23.5325 6.63827 24.092 5.90028 24.8105C5.01528 25.688 5.34378 26.759 6.54077 27.206C7.90126 27.716 9.32925 27.731 10.7557 27.557C12.4447 27.3485 14.1007 27.077 15.9397 26.822C13.7902 27.827 11.6737 28.5319 9.44475 28.8169C7.88476 29.0269 6.32777 29.1379 4.78579 28.6909C2.57181 28.0685 1.58631 26.4395 2.16081 24.251C2.7023 22.2065 4.01479 20.5775 5.42478 19.076C10.1332 14.0781 16.0867 11.5401 22.9746 11.0286C24.5826 10.9176 26.2071 11.1246 27.7146 11.7951C29.8311 12.7536 30.7176 14.7801 29.6841 16.8261C29.0121 18.1835 28.0761 19.4285 27.1416 20.6585C26.2236 21.872 25.1901 22.9895 24.2226 24.155C23.9436 24.506 23.6811 24.875 23.4681 25.2725C23.0571 26.0225 23.3361 26.5175 24.2061 26.4395C26.0256 26.2625 27.8811 26.12 29.6361 25.673C32.2101 25.0175 34.7195 24.092 37.262 23.2775C37.5245 23.213 37.7705 23.117 38 23.0225V23.021Z" fill="currentColor"/>
 </svg>

+ 2 - 2
packages/ui/src/assets/icons/provider/alibaba.svg

@@ -1,3 +1,3 @@
-<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
-  <path d="M24 14.014c-2.8 1.512-5.62 2.896-8.759 3.524-.7.139-1.476.139-2.187.043-.678-.085-1.017-.682-.776-1.31.23-.585.536-1.181.93-1.671.852-1.065 1.814-2.034 2.678-3.088a15.75 15.75 0 001.422-2.054c.306-.511.164-1.129-.372-1.384-.897-.437-1.859-.745-2.81-1.075-.11-.043-.274.074-.492.149.273.244.47.425.743.67-2.821.48-5.49 1.16-8.08 2.098-.012.053-.033.095-.023.117.383.585.208 1.032-.35 1.394a2.365 2.365 0 00-.568.522c1.706.5 3.226.213 4.68-.735-.087-.127-.175-.244-.262-.372.546.096.874.394.918.862.011.107-.054.213-.087.32-.077-.086-.175-.17-.24-.267-.045-.064-.056-.138-.088-.245-1.728 1.15-3.587 1.438-5.632.842 0 .404-.022.745.011 1.075.022.287-.098.415-.36.564-.591.362-1.204.735-1.696 1.214-.59.585-.371 1.299.427 1.597.907.34 1.859.35 2.81.234 1.126-.139 2.23-.32 3.456-.49-1.433.67-2.844 1.14-4.33 1.33-1.04.14-2.078.214-3.106-.084-1.476-.415-2.133-1.501-1.75-2.96.361-1.363 1.236-2.449 2.176-3.45 3.139-3.332 7.108-5.024 11.7-5.365 1.072-.074 2.155.064 3.16.511 1.411.639 2.002 1.99 1.313 3.354-.448.905-1.072 1.735-1.695 2.555-.612.809-1.301 1.554-1.946 2.331-.186.234-.361.48-.503.745-.274.5-.088.83.492.778 1.213-.118 2.45-.213 3.62-.511 1.716-.437 3.389-1.054 5.084-1.597.175-.043.339-.107.492-.17z"></path>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M37.9998 23.021C33.7998 25.2889 29.5698 27.3649 24.8614 28.3069C23.8114 28.5154 22.6474 28.5154 21.5809 28.3714C20.5639 28.2439 20.0554 27.3484 20.4169 26.4064C20.7619 25.5289 21.2209 24.635 21.8119 23.9C23.0899 22.3025 24.5329 20.849 25.8289 19.268C26.6203 18.2991 27.3335 17.2689 27.9618 16.187C28.4208 15.4205 28.2078 14.4935 27.4038 14.111C26.0584 13.4556 24.6154 12.9936 23.1889 12.4986C23.0239 12.4341 22.7779 12.6096 22.4509 12.7221C22.8604 13.0881 23.1559 13.3596 23.5654 13.727C19.3339 14.447 15.3305 15.467 11.4455 16.874C11.4275 16.9535 11.396 17.0165 11.411 17.0495C11.9855 17.927 11.723 18.5975 10.886 19.1405C10.5611 19.3531 10.2732 19.6176 10.034 19.9235C12.593 20.6735 14.873 20.243 17.0539 18.821C16.9234 18.6305 16.7914 18.455 16.6609 18.263C17.4799 18.407 17.9719 18.854 18.0379 19.556C18.0544 19.7165 17.9569 19.8755 17.9074 20.036C17.7919 19.907 17.6449 19.781 17.5474 19.6355C17.4799 19.5395 17.4634 19.4285 17.4154 19.268C14.8235 20.993 12.035 21.425 8.96751 20.531C8.96751 21.137 8.93451 21.6485 8.98401 22.1435C9.01701 22.574 8.83701 22.766 8.44401 22.9895C7.55752 23.5325 6.63803 24.092 5.90003 24.8105C5.01504 25.6879 5.34354 26.7589 6.54053 27.2059C7.90102 27.7159 9.329 27.7309 10.7555 27.5569C12.4445 27.3484 14.1005 27.0769 15.9394 26.8219C13.79 27.8269 11.6735 28.5319 9.4445 28.8169C7.88452 29.0269 6.32753 29.1379 4.78554 28.6909C2.57156 28.0684 1.58607 26.4394 2.16057 24.251C2.70206 22.2065 4.01455 20.5775 5.42454 19.076C10.133 14.078 16.0864 11.5401 22.9744 11.0286C24.5824 10.9176 26.2069 11.1246 27.7143 11.7951C29.8308 12.7536 30.7173 14.78 29.6838 16.826C29.0118 18.1835 28.0758 19.4285 27.1413 20.6585C26.2234 21.872 25.1899 22.9895 24.2224 24.155C23.9434 24.506 23.6809 24.875 23.4679 25.2724C23.0569 26.0224 23.3359 26.5174 24.2059 26.4394C26.0254 26.2624 27.8808 26.1199 29.6358 25.6729C32.2098 25.0174 34.7193 24.092 37.2618 23.2775C37.5243 23.213 37.7703 23.117 37.9998 23.0225V23.021Z" fill="currentColor"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 1 - 3
packages/ui/src/assets/icons/provider/amazon-bedrock.svg


+ 3 - 7
packages/ui/src/assets/icons/provider/anthropic.svg

@@ -1,7 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
-  <!-- https://icones.js.org/collection/ri?s=anthropic&icon=ri:anthropic-fill -->
-  <path
-    fill="currentColor"
-    d="M16.765 5h-3.308l5.923 15h3.23zM7.226 5L1.38 20h3.308l1.307-3.154h6.154l1.23 3.077h3.309L10.688 5zm-.308 9.077l2-5.308l2.077 5.308z"
-  />
-</svg>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M26.9568 9.88184H22.1265L30.7753 31.7848H35.4917L26.9568 9.88184ZM13.028 9.88184L4.4917 31.7848H9.32203L11.2305 27.1793H20.2166L22.0126 31.6724H26.8444L18.0832 9.88184H13.028ZM12.5783 23.1361L15.4987 15.3853L18.5315 23.1361H12.5783Z" fill="currentColor"/>
+</svg>

+ 2 - 3
packages/ui/src/assets/icons/provider/azure.svg

@@ -1,4 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
-  <!-- https://api.iconify.design/mdi:microsoft-azure.svg -->
-  <path fill="currentColor" d="M13.05 4.24L6.56 18.05L2 18l5.09-8.76zm.7 1.09L22 19.76H6.74l9.3-1.66l-4.87-5.79z"/>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M21.68 7.58398L11.296 29.68L4 29.6L12.144 15.584L21.68 7.58398ZM22.8 9.32798L36 32.416H11.584L26.464 29.76L18.672 20.496L22.8 9.32798Z" fill="currentColor"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
packages/ui/src/assets/icons/provider/bailing.svg


+ 3 - 1
packages/ui/src/assets/icons/provider/baseten.svg

@@ -1 +1,3 @@
-<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Baseten</title><path d="M2.316 4.8h14.682v4.8H7.31a.302.302 0 00-.308.3v4.2c0 .171.14.3.308.3h9.688v4.8h-4.686a.302.302 0 00-.308.3v4.2c0 .171.141.3.308.3h4.378a.297.297 0 00.308-.3v-4.5h4.694a.302.302 0 00.308-.3v-4.2c0-.171-.14-.3-.308-.3h-4.694V9.6h4.694A.302.302 0 0022 9.3V5.1c0-.171-.14-.3-.308-.3h-4.694V.3c0-.171-.14-.3-.308-.3H2.316A.31.31 0 002 .3v4.2c0 .171.14.3.316.3z"></path></svg>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.97934 6.78009H15.6237V10.26H8.59995C8.57096 10.2595 8.54214 10.2647 8.51516 10.2753C8.48819 10.286 8.4636 10.3019 8.44283 10.3221C8.42205 10.3423 8.40551 10.3665 8.39415 10.3932C8.38279 10.4199 8.37684 10.4485 8.37665 10.4775V13.5225C8.37665 13.6465 8.47815 13.74 8.59995 13.74H15.6237V17.22H12.2264C12.1974 17.2194 12.1685 17.2246 12.1416 17.2352C12.1146 17.2459 12.09 17.2618 12.0692 17.282C12.0485 17.3023 12.0319 17.3264 12.0206 17.3531C12.0092 17.3798 12.0032 17.4085 12.0031 17.4375V20.4824C12.0031 20.6064 12.1053 20.6999 12.2264 20.6999H15.4004C15.4295 20.701 15.4585 20.6962 15.4857 20.6857C15.5129 20.6752 15.5377 20.6593 15.5586 20.639C15.5795 20.6187 15.596 20.5943 15.6072 20.5674C15.6184 20.5405 15.624 20.5116 15.6237 20.4824V17.22H19.0268C19.0558 17.2205 19.0846 17.2154 19.1116 17.2047C19.1385 17.194 19.1631 17.1781 19.1839 17.1579C19.2047 17.1377 19.2212 17.1135 19.2326 17.0868C19.2439 17.0601 19.2499 17.0315 19.2501 17.0025V13.9575C19.2501 13.8335 19.1486 13.74 19.0268 13.74H15.6237V10.26H19.0268C19.0558 10.2606 19.0846 10.2554 19.1116 10.2448C19.1385 10.2341 19.1631 10.2182 19.1839 10.198C19.2047 10.1777 19.2212 10.1536 19.2326 10.1269C19.2439 10.1002 19.2499 10.0715 19.2501 10.0425V6.99758C19.2501 6.87361 19.1486 6.78009 19.0268 6.78009H15.6237V3.51762C15.6237 3.39365 15.5222 3.30012 15.4004 3.30012H4.97934C4.92022 3.29895 4.86302 3.32112 4.82014 3.36183C4.77725 3.40255 4.75214 3.45852 4.75024 3.51762V6.56259C4.75024 6.68656 4.85174 6.78009 4.97934 6.78009Z" fill="currentColor"/>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 1 - 2
packages/ui/src/assets/icons/provider/cerebras.svg


+ 3 - 5
packages/ui/src/assets/icons/provider/cloudflare-ai-gateway.svg

@@ -1,6 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="256" height="256" viewBox="0 0 256 256">
-    <g>
-        <path fill="currentColor" d="M205.52 119.813C204.662 119.813 203.815 119.843 202.969 119.871C202.832 119.878 202.697 119.911 202.571 119.965C202.347 120.042 202.146 120.173 201.985 120.346C201.825 120.52 201.71 120.73 201.651 120.959L198.023 133.631C196.458 139.08 197.04 144.111 199.669 147.805C202.079 151.221 206.089 153.226 210.958 153.46L230.637 154.654C231.222 154.684 231.729 154.966 232.037 155.43C232.198 155.678 232.3 155.96 232.335 156.253C232.37 156.547 232.336 156.844 232.237 157.122C232.079 157.575 231.793 157.973 231.415 158.268C231.036 158.562 230.581 158.742 230.103 158.784L209.655 159.977C198.545 160.492 186.593 169.557 182.4 180.61L180.926 184.51C180.863 184.672 180.839 184.847 180.856 185.019C180.874 185.192 180.932 185.358 181.027 185.504C181.121 185.65 181.249 185.771 181.4 185.857C181.551 185.943 181.72 185.993 181.893 186H252.318C252.728 186.002 253.126 185.87 253.453 185.623C253.78 185.377 254.017 185.03 254.128 184.635C255.379 180.14 256.009 175.495 256 170.828C256 142.668 233.418 119.844 205.551 119.844" />
-        <path fill="currentColor" d="M174.782 184.362L176.085 179.779C177.653 174.33 177.072 169.299 174.446 165.606C172.028 162.189 168.022 160.184 163.15 159.95L70.838 158.757C70.5509 158.752 70.269 158.679 70.0155 158.544C69.7619 158.409 69.5438 158.216 69.379 157.981C69.217 157.734 69.1143 157.452 69.0791 157.158C69.0439 156.865 69.0771 156.567 69.176 156.288C69.3358 155.832 69.6243 155.433 70.0067 155.138C70.389 154.843 70.8487 154.665 71.33 154.626L164.503 153.433C175.566 152.922 187.518 143.853 191.711 132.8L197.024 118.76C197.238 118.164 197.294 117.522 197.18 116.9C191.126 89.51 166.91 69 137.96 69C111.269 69 88.626 86.403 80.5 110.596C75.0295 106.437 68.1787 104.52 61.344 105.237C48.549 106.524 38.25 116.946 36.979 129.88C36.6502 133.11 36.8878 136.373 37.681 139.522C16.773 140.145 0 157.454 0 178.726C0 180.649 0.137 182.544 0.413 184.393C0.528 185.29 1.292 185.963 2.196 185.961H172.676C173.156 185.953 173.62 185.79 174 185.496C174.38 185.202 174.654 184.794 174.782 184.331" />
-    </g>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.6323 11.3946C17.57 11.3946 17.5085 11.3968 17.447 11.3988C17.437 11.3993 17.4272 11.4017 17.4181 11.4057C17.4018 11.4113 17.3872 11.4208 17.3755 11.4333C17.3639 11.446 17.3555 11.4612 17.3512 11.4779L17.0876 12.3986C16.9739 12.7945 17.0162 13.16 17.2072 13.4284C17.3823 13.6766 17.6737 13.8223 18.0274 13.8393L19.4572 13.926C19.4998 13.9282 19.5366 13.9487 19.559 13.9824C19.5707 14.0004 19.5781 14.0209 19.5806 14.0422C19.5832 14.0636 19.5807 14.0852 19.5735 14.1054C19.562 14.1383 19.5412 14.1672 19.5138 14.1886C19.4862 14.21 19.4532 14.2231 19.4185 14.2261L17.9328 14.3128C17.1256 14.3502 16.2572 15.0088 15.9525 15.8119L15.8454 16.0953C15.8409 16.107 15.8391 16.1197 15.8404 16.1322C15.8417 16.1448 15.8459 16.1569 15.8528 16.1675C15.8596 16.1781 15.8689 16.1869 15.8799 16.1931C15.8908 16.1994 15.9031 16.203 15.9157 16.2035H21.0325C21.0623 16.2037 21.0912 16.1941 21.115 16.1761C21.1387 16.1583 21.156 16.133 21.164 16.1043C21.2549 15.7778 21.3007 15.4403 21.3 15.1012C21.3 13.0552 19.6593 11.3969 17.6346 11.3969" fill="currentColor"/>
+<path d="M15.3989 16.0845L15.4936 15.7515C15.6075 15.3556 15.5653 14.9901 15.3745 14.7218C15.1989 14.4735 14.9078 14.3278 14.5538 14.3108L7.84677 14.2241C7.82591 14.2238 7.80543 14.2185 7.78701 14.2087C7.76859 14.1988 7.75274 14.1848 7.74077 14.1678C7.729 14.1498 7.72153 14.1293 7.71898 14.108C7.71642 14.0867 7.71883 14.065 7.72602 14.0447C7.73763 14.0116 7.75859 13.9826 7.78637 13.9612C7.81415 13.9398 7.84755 13.9268 7.88252 13.924L14.6521 13.8373C15.4559 13.8002 16.3243 13.1413 16.6289 12.3382L17.015 11.3181C17.0305 11.2748 17.0346 11.2282 17.0263 11.183C16.5864 9.19291 14.827 7.70273 12.7236 7.70273C10.7843 7.70273 9.13918 8.96716 8.54878 10.7249C8.15131 10.4228 7.65356 10.2835 7.15697 10.3356C6.22734 10.4291 5.47905 11.1863 5.38671 12.126C5.36282 12.3607 5.38008 12.5978 5.43771 12.8266C3.91861 12.8719 2.69995 14.1295 2.69995 15.675C2.69995 15.8147 2.70991 15.9524 2.72996 16.0867C2.73831 16.1519 2.79382 16.2008 2.8595 16.2007H15.2459C15.2808 16.2001 15.3145 16.1882 15.3421 16.1669C15.3697 16.1455 15.3896 16.1159 15.3989 16.0822" fill="currentColor"/>
 </svg>

+ 3 - 5
packages/ui/src/assets/icons/provider/cloudflare-workers-ai.svg

@@ -1,6 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="256" height="256" viewBox="0 0 256 256">
-    <g>
-        <path fill="currentColor" d="M205.52 119.813C204.662 119.813 203.815 119.843 202.969 119.871C202.832 119.878 202.697 119.911 202.571 119.965C202.347 120.042 202.146 120.173 201.985 120.346C201.825 120.52 201.71 120.73 201.651 120.959L198.023 133.631C196.458 139.08 197.04 144.111 199.669 147.805C202.079 151.221 206.089 153.226 210.958 153.46L230.637 154.654C231.222 154.684 231.729 154.966 232.037 155.43C232.198 155.678 232.3 155.96 232.335 156.253C232.37 156.547 232.336 156.844 232.237 157.122C232.079 157.575 231.793 157.973 231.415 158.268C231.036 158.562 230.581 158.742 230.103 158.784L209.655 159.977C198.545 160.492 186.593 169.557 182.4 180.61L180.926 184.51C180.863 184.672 180.839 184.847 180.856 185.019C180.874 185.192 180.932 185.358 181.027 185.504C181.121 185.65 181.249 185.771 181.4 185.857C181.551 185.943 181.72 185.993 181.893 186H252.318C252.728 186.002 253.126 185.87 253.453 185.623C253.78 185.377 254.017 185.03 254.128 184.635C255.379 180.14 256.009 175.495 256 170.828C256 142.668 233.418 119.844 205.551 119.844" />
-        <path fill="currentColor" d="M174.782 184.362L176.085 179.779C177.653 174.33 177.072 169.299 174.446 165.606C172.028 162.189 168.022 160.184 163.15 159.95L70.838 158.757C70.5509 158.752 70.269 158.679 70.0155 158.544C69.7619 158.409 69.5438 158.216 69.379 157.981C69.217 157.734 69.1143 157.452 69.0791 157.158C69.0439 156.865 69.0771 156.567 69.176 156.288C69.3358 155.832 69.6243 155.433 70.0067 155.138C70.389 154.843 70.8487 154.665 71.33 154.626L164.503 153.433C175.566 152.922 187.518 143.853 191.711 132.8L197.024 118.76C197.238 118.164 197.294 117.522 197.18 116.9C191.126 89.51 166.91 69 137.96 69C111.269 69 88.626 86.403 80.5 110.596C75.0295 106.437 68.1787 104.52 61.344 105.237C48.549 106.524 38.25 116.946 36.979 129.88C36.6502 133.11 36.8878 136.373 37.681 139.522C16.773 140.145 0 157.454 0 178.726C0 180.649 0.137 182.544 0.413 184.393C0.528 185.29 1.292 185.963 2.196 185.961H172.676C173.156 185.953 173.62 185.79 174 185.496C174.38 185.202 174.654 184.794 174.782 184.331" />
-    </g>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.6323 11.3946C17.57 11.3946 17.5085 11.3968 17.447 11.3988C17.437 11.3993 17.4272 11.4017 17.4181 11.4057C17.4018 11.4113 17.3872 11.4208 17.3755 11.4333C17.3639 11.446 17.3555 11.4612 17.3512 11.4779L17.0876 12.3986C16.9739 12.7945 17.0162 13.16 17.2072 13.4284C17.3823 13.6766 17.6737 13.8223 18.0274 13.8393L19.4572 13.926C19.4998 13.9282 19.5366 13.9487 19.559 13.9824C19.5707 14.0004 19.5781 14.0209 19.5806 14.0422C19.5832 14.0636 19.5807 14.0852 19.5735 14.1054C19.562 14.1383 19.5412 14.1672 19.5138 14.1886C19.4862 14.21 19.4532 14.2231 19.4185 14.2261L17.9328 14.3128C17.1256 14.3502 16.2572 15.0088 15.9525 15.8119L15.8454 16.0953C15.8409 16.107 15.8391 16.1197 15.8404 16.1322C15.8417 16.1448 15.8459 16.1569 15.8528 16.1675C15.8596 16.1781 15.8689 16.1869 15.8799 16.1931C15.8908 16.1994 15.9031 16.203 15.9157 16.2035H21.0325C21.0623 16.2037 21.0912 16.1941 21.115 16.1761C21.1387 16.1583 21.156 16.133 21.164 16.1043C21.2549 15.7778 21.3007 15.4403 21.3 15.1012C21.3 13.0552 19.6593 11.3969 17.6346 11.3969" fill="currentColor"/>
+<path d="M15.3989 16.0845L15.4936 15.7515C15.6075 15.3556 15.5653 14.9901 15.3745 14.7218C15.1989 14.4735 14.9078 14.3278 14.5538 14.3108L7.84677 14.2241C7.82591 14.2238 7.80543 14.2185 7.78701 14.2087C7.76859 14.1988 7.75274 14.1848 7.74077 14.1678C7.729 14.1498 7.72153 14.1293 7.71898 14.108C7.71642 14.0867 7.71883 14.065 7.72602 14.0447C7.73763 14.0116 7.75859 13.9826 7.78637 13.9612C7.81415 13.9398 7.84755 13.9268 7.88252 13.924L14.6521 13.8373C15.4559 13.8002 16.3243 13.1413 16.6289 12.3382L17.015 11.3181C17.0305 11.2748 17.0346 11.2282 17.0263 11.183C16.5864 9.19291 14.827 7.70273 12.7236 7.70273C10.7843 7.70273 9.13918 8.96716 8.54878 10.7249C8.15131 10.4228 7.65356 10.2835 7.15697 10.3356C6.22734 10.4291 5.47905 11.1863 5.38671 12.126C5.36282 12.3607 5.38008 12.5978 5.43771 12.8266C3.91861 12.8719 2.69995 14.1295 2.69995 15.675C2.69995 15.8147 2.70991 15.9524 2.72996 16.0867C2.73831 16.1519 2.79382 16.2008 2.8595 16.2007H15.2459C15.2808 16.2001 15.3145 16.1882 15.3421 16.1669C15.3697 16.1455 15.3896 16.1159 15.3989 16.0822" fill="currentColor"/>
 </svg>

+ 4 - 18
packages/ui/src/assets/icons/provider/cohere.svg

@@ -1,19 +1,5 @@
-<svg version="1.1" id="Layer_1"
-	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 75 75"
-	 xml:space="preserve">
-<g>
-	<g>
-		<g>
-			<path fill="currentColor"
-				  d="M24.3,44.7c2,0,6-0.1,11.6-2.4c6.5-2.7,19.3-7.5,28.6-12.5c6.5-3.5,9.3-8.1,9.3-14.3C73.8,7,66.9,0,58.3,0 h-36C10,0,0,10,0,22.3S9.4,44.7,24.3,44.7z">
-			</path>
-			<path fill="currentColor"
-				  d="M30.4,60c0-6,3.6-11.5,9.2-13.8l11.3-4.7C62.4,36.8,75,45.2,75,57.6C75,67.2,67.2,75,57.6,75l-12.3,0C37.1,75,30.4,68.3,30.4,60z">
-			</path>
-			<path fill="currentColor"
-				  d="M12.9,47.6L12.9,47.6C5.8,47.6,0,53.4,0,60.5v1.7C0,69.2,5.8,75,12.9,75h0c7.1,0,12.9-5.8,12.9-12.9v-1.7C25.7,53.4,20,47.6,12.9,47.6z">
-			</path>
-		</g>
-	</g>
-</g>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.14882 13.5552C9.58082 13.5552 10.4448 13.5336 11.6544 13.0368C13.0584 12.4536 15.8232 11.4168 17.832 10.3368C19.236 9.5808 19.8408 8.5872 19.8408 7.248C19.8408 5.412 18.3504 3.9 16.4928 3.9H8.71682C6.06002 3.9 3.90002 6.06 3.90002 8.7168C3.90002 11.3736 5.93042 13.5552 9.14882 13.5552Z" fill="currentColor"/>
+<path d="M10.4664 16.86C10.4664 15.564 11.244 14.376 12.4536 13.8792L14.8944 12.864C17.3784 11.8488 20.1 13.6632 20.1 16.3416C20.1 18.4152 18.4152 20.1 16.3416 20.1H13.6848C11.9136 20.1 10.4664 18.6528 10.4664 16.86Z" fill="currentColor"/>
+<path d="M6.68642 14.1816C5.15282 14.1816 3.90002 15.4344 3.90002 16.968V17.3352C3.90002 18.8472 5.15282 20.1 6.68642 20.1C8.22003 20.1 9.47283 18.8472 9.47283 17.3136V16.9464C9.45123 15.4344 8.22003 14.1816 6.68642 14.1816Z" fill="currentColor"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
packages/ui/src/assets/icons/provider/deepinfra.svg


Разница между файлами не показана из-за своего большого размера
+ 0 - 1
packages/ui/src/assets/icons/provider/deepseek.svg


+ 2 - 2
packages/ui/src/assets/icons/provider/fastrouter.svg

@@ -1,3 +1,3 @@
-<svg viewBox="0 0 512 512" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
-    <path d="M446 102.557L384.138 205.895V150.147H260.022L220.061 219.032C217.678 222.612 217.678 227.385 219.464 230.965C221.847 234.545 225.42 236.932 230.185 236.932H362.997L183.731 512L218.274 347.317C218.869 343.737 218.273 340.156 215.891 337.173C213.509 334.19 209.936 332.997 206.363 332.997H67L162.268 54.8009H229.093V54.6366L384.138 54.8009V0L446 102.557Z"/>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M31.8828 10.4098L28.0164 16.8684V13.3842H20.2592L17.7616 17.6895C17.6127 17.9132 17.6127 18.2116 17.7243 18.4353C17.8733 18.6591 18.0966 18.8083 18.3944 18.8083H26.6951L15.491 36L17.6499 25.7073C17.6871 25.4836 17.6499 25.2598 17.501 25.0733C17.3521 24.8869 17.1288 24.8123 16.9055 24.8123H8.19531L14.1496 7.42506H18.3261V7.41479L28.0164 7.42506V4L31.8828 10.4098Z" fill="currentColor"/>
 </svg>

+ 2 - 2
packages/ui/src/assets/icons/provider/fireworks-ai.svg

@@ -1,3 +1,3 @@
-<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
-  <path clip-rule="evenodd" d="M14.8 5l-2.801 6.795L9.195 5H7.397l3.072 7.428a1.64 1.64 0 003.038.002L16.598 5H14.8zm1.196 10.352l5.124-5.244-.699-1.669-5.596 5.739a1.664 1.664 0 00-.343 1.807 1.642 1.642 0 001.516 1.012L16 17l8-.02-.699-1.669-7.303.041h-.002zM2.88 10.104l.699-1.669 5.596 5.739c.468.479.603 1.189.343 1.807a1.643 1.643 0 01-1.516 1.012l-8-.018-.002.002.699-1.669 7.303.042-5.122-5.246z"></path>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.45 5.74999L11.9991 11.6956L9.54562 5.74999H7.97237L10.6604 12.2495C10.7678 12.5138 10.9515 12.7402 11.1882 12.8996C11.4248 13.059 11.7036 13.1442 11.9889 13.1444C12.2742 13.1446 12.5531 13.0597 12.79 12.9006C13.0268 12.7415 13.2109 12.5154 13.3186 12.2512L16.0232 5.74999H14.45ZM15.4965 14.808L19.98 10.2195L19.3684 8.75911L14.4719 13.7807C14.272 13.9856 14.1369 14.2448 14.0835 14.5261C14.0301 14.8073 14.0608 15.098 14.1718 15.3619C14.2807 15.624 14.4648 15.848 14.7008 16.0056C14.9369 16.1632 15.2144 16.2473 15.4983 16.2474L15.5 16.25L22.5 16.2325L21.8884 14.7721L15.4983 14.808H15.4965ZM4.02 10.216L4.63162 8.75561L9.52813 13.7772C9.93763 14.1964 10.0557 14.8176 9.82825 15.3584C9.71925 15.6204 9.53511 15.8443 9.29905 16.0019C9.06299 16.1595 8.78557 16.2437 8.50175 16.2439L1.50175 16.2281L1.5 16.2299L2.11163 14.7695L8.50175 14.8062L4.02 10.216Z" fill="currentColor"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 1 - 4
packages/ui/src/assets/icons/provider/github-copilot.svg


+ 3 - 4
packages/ui/src/assets/icons/provider/github-models.svg

@@ -1,4 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
-  <!-- https://api.iconify.design/ri:github-fill.svg -->
-  <path fill="currentColor" d="M12.001 2c-5.525 0-10 4.475-10 10a9.99 9.99 0 0 0 6.837 9.488c.5.087.688-.213.688-.476c0-.237-.013-1.024-.013-1.862c-2.512.463-3.162-.612-3.362-1.175c-.113-.288-.6-1.175-1.025-1.413c-.35-.187-.85-.65-.013-.662c.788-.013 1.35.725 1.538 1.025c.9 1.512 2.337 1.087 2.912.825c.088-.65.35-1.087.638-1.337c-2.225-.25-4.55-1.113-4.55-4.938c0-1.088.387-1.987 1.025-2.687c-.1-.25-.45-1.275.1-2.65c0 0 .837-.263 2.75 1.024a9.3 9.3 0 0 1 2.5-.337c.85 0 1.7.112 2.5.337c1.913-1.3 2.75-1.024 2.75-1.024c.55 1.375.2 2.4.1 2.65c.637.7 1.025 1.587 1.025 2.687c0 3.838-2.337 4.688-4.562 4.938c.362.312.675.912.675 1.85c0 1.337-.013 2.412-.013 2.75c0 .262.188.574.688.474A10.02 10.02 0 0 0 22 12c0-5.525-4.475-10-10-10"/>
-  </svg>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M20.0015 4.4704C11.4373 4.4704 4.50074 11.407 4.50074 19.9712C4.49793 23.2252 5.52031 26.3975 7.42272 29.0376C9.32512 31.6776 12.0109 33.6513 15.0986 34.6783C15.8737 34.8132 16.1651 34.3481 16.1651 33.9405C16.1651 33.5731 16.1449 32.3532 16.1449 31.0542C12.2511 31.7719 11.2436 30.1056 10.9336 29.2329C10.7584 28.7865 10.0035 27.4115 9.34473 27.0426C8.8022 26.7528 8.02716 26.0351 9.32458 26.0165C10.546 25.9963 11.4172 27.1403 11.7086 27.6053C13.1037 29.949 15.3311 29.2902 16.2224 28.8841C16.3588 27.8766 16.7649 27.1992 17.2114 26.8117C13.7624 26.4241 10.1585 25.0864 10.1585 19.1574C10.1585 17.4709 10.7584 16.0774 11.7473 14.9923C11.5923 14.6048 11.0498 13.016 11.9024 10.8846C11.9024 10.8846 13.1998 10.4769 16.1651 12.4719C17.4271 12.1226 18.7308 11.9468 20.0403 11.9495C21.3578 11.9495 22.6754 12.1231 23.9155 12.4719C26.8808 10.4568 28.1782 10.8846 28.1782 10.8846C29.0307 13.016 28.4882 14.6048 28.3332 14.9923C29.3206 16.0774 29.922 17.4523 29.922 19.1574C29.922 25.1066 26.2995 26.4241 22.8506 26.8117C23.4117 27.2953 23.8969 28.2253 23.8969 29.6793C23.8969 31.7518 23.8767 33.4181 23.8767 33.942C23.8767 34.3481 24.1681 34.8318 24.9432 34.6768C28.0193 33.6368 30.6922 31.6589 32.5859 29.0211C34.4796 26.3833 35.499 23.2183 35.5007 19.9712C35.5007 11.407 28.5641 4.4704 20 4.4704" fill="currentColor"/>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 4 - 2
packages/ui/src/assets/icons/provider/google-vertex.svg


+ 2 - 6
packages/ui/src/assets/icons/provider/google.svg

@@ -1,7 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
- <!-- https://icones.js.org/collection/ri?s=gemini&icon=ri:gemini-fill -->
-  <path
-    fill="currentColor"
-    d="M24 12.024c-6.437.388-11.59 5.539-11.977 11.976h-.047C11.588 17.563 6.436 12.412 0 12.024v-.047C6.437 11.588 11.588 6.437 11.976 0h.047c.388 6.437 5.54 11.588 11.977 11.977z"
-  />
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M37 20.034C27.8809 20.5837 20.5808 27.8809 20.0326 37H19.966C19.4163 27.8809 12.1177 20.5837 3 20.034V19.9674C12.1191 19.4163 19.4163 12.1191 19.966 3H20.0326C20.5822 12.1191 27.8809 19.4163 37 19.9674V20.034Z" fill="currentColor"/>
 </svg>

+ 2 - 2
packages/ui/src/assets/icons/provider/groq.svg

@@ -1,3 +1,3 @@
-<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
-  <path d="M12.036 2c-3.853-.035-7 3-7.036 6.781-.035 3.782 3.055 6.872 6.908 6.907h2.42v-2.566h-2.292c-2.407.028-4.38-1.866-4.408-4.23-.029-2.362 1.901-4.298 4.308-4.326h.1c2.407 0 4.358 1.915 4.365 4.278v6.305c0 2.342-1.944 4.25-4.323 4.279a4.375 4.375 0 01-3.033-1.252l-1.851 1.818A7 7 0 0012.029 22h.092c3.803-.056 6.858-3.083 6.879-6.816v-6.5C18.907 4.963 15.817 2 12.036 2z"></path>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M20.056 4.50022C14.0839 4.44597 9.20616 9.15015 9.15036 15.0106C9.09611 20.8726 13.8855 25.6621 19.8576 25.7163H23.6085V21.7391H20.056C16.3252 21.7825 13.2671 18.8468 13.2237 15.1827C13.1787 11.5216 16.1702 8.52086 19.901 8.47746H20.056C23.7868 8.47746 26.8108 11.4457 26.8216 15.1083V24.8809C26.8216 28.5109 23.8085 31.4683 20.1211 31.5132C18.3617 31.5007 16.6759 30.8049 15.42 29.5726L12.551 32.3905C14.5529 34.3571 17.239 35.4715 20.0451 35.4998H20.1877C26.0823 35.413 30.8175 30.7212 30.85 24.9351V14.8603C30.7059 9.0928 25.9165 4.50022 20.056 4.50022Z" fill="currentColor"/>
 </svg>

+ 5 - 2
packages/ui/src/assets/icons/provider/helicone.svg

@@ -1,3 +1,6 @@
-<svg width="1000" height="1000" viewBox="0 0 1000 1000" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M115.919 282.24L494.502 116.609C498.007 115.076 501.993 115.076 505.498 116.609L884.081 282.24M115.919 282.24V628.599M115.919 282.24L413.778 412.553M884.081 282.24L781.203 327.249M884.081 282.24V371.401M500 885.796V758.912M500 885.796L585.732 849.819M500 885.796L150.212 739.01M500 450.275L781.203 327.249M500 450.275L413.778 412.553M500 450.275V487.997M500 758.912L781.203 327.249M500 758.912V487.997M585.732 849.819L875.672 728.148C880.767 726.01 884.081 721.024 884.081 715.499V371.401M585.732 849.819L884.081 371.401M115.919 628.599V715.499C115.919 721.024 119.233 726.01 124.328 728.148L150.212 739.01M115.919 628.599L413.778 412.553M150.212 739.01L500 487.997" stroke="currentColor" stroke-width="27.4344" stroke-linecap="round" stroke-linejoin="round"/>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.3697 8.08776L12 10.8745V11.7289V17.8656L18.3697 8.08776Z" fill="currentColor" fill-opacity="0.25"/>
+<path d="M3.30005 7.06824V14.9138L10.047 10.02L3.30005 7.06824Z" fill="currentColor" fill-opacity="0.25"/>
+<path d="M11.8755 3.31646L3.30005 7.06824L10.047 10.02L12 10.8745L18.3697 8.08776L20.7 7.06824L12.1246 3.31646C12.0452 3.28173 11.9549 3.28173 11.8755 3.31646Z" fill="currentColor" fill-opacity="0.35"/>
+<path d="M3.30005 7.06824L11.8755 3.31646C11.9549 3.28173 12.0452 3.28173 12.1246 3.31646L20.7 7.06824M3.30005 7.06824V14.9138M3.30005 7.06824L10.047 10.02M20.7 7.06824L18.3697 8.08776M20.7 7.06824V9.08787M3.30005 14.9138V16.8822C3.30005 17.0073 3.37512 17.1203 3.49053 17.1687L4.07684 17.4148M3.30005 14.9138L10.047 10.02M10.047 10.02L12 10.8745M18.3697 8.08776L12 10.8745M18.3697 8.08776L12 17.8656M20.7 9.08787V16.8822C20.7 17.0073 20.625 17.1203 20.5096 17.1687L13.942 19.9247M20.7 9.08787L13.942 19.9247M12 20.7397V17.8656M12 20.7397L13.942 19.9247M12 20.7397L4.07684 17.4148M12 17.8656V11.7289M4.07684 17.4148L12 11.7289M12 10.8745V11.7289" stroke="currentColor" stroke-width="0.62143" stroke-linecap="round" stroke-linejoin="round"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
packages/ui/src/assets/icons/provider/huggingface.svg


Разница между файлами не показана из-за своего большого размера
+ 0 - 1
packages/ui/src/assets/icons/provider/iflowcn.svg


+ 3 - 8
packages/ui/src/assets/icons/provider/inception.svg

@@ -1,9 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 149.64 150.39">
-  <g id="Layer_1-2" data-name="Layer 1">
-    <g>
-      <polygon fill="currentColor" points="94.7 0 47.35 0 0 47.35 0 94.7 47.35 94.7 47.35 47.35 94.7 47.35 94.7 0"/>
-      <polygon fill="currentColor" points="102.29 55.69 102.29 103.04 54.94 103.04 54.94 150.39 102.29 150.39 149.64 103.04 149.64 55.69 102.29 55.69"/>
-    </g>
-  </g>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.3794 2.99999H8.71219L3.04492 8.66725V14.3345H8.71219V8.66725H14.3794V2.99999Z" fill="currentColor"/>
+<path d="M15.2877 9.66548V15.3327H9.62048V21H15.2877L20.955 15.3327V9.66548H15.2877Z" fill="currentColor"/>
 </svg>

+ 2 - 2
packages/ui/src/assets/icons/provider/inference.svg

@@ -1,3 +1,3 @@
-<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
-  <path d="M22 21.376h-4.89V2.62H22v18.756zM14.532 21.376h-3.469V2.62h3.469v18.756zM8.764 21.376h-2.66V2.62h2.66v18.756zM3.903 21.376H2V2.62h1.903v18.756z"></path>
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M34.625 33.7119H27.4734V6.28124H34.625V33.7119ZM23.703 33.7119H18.6296V6.28124H23.703V33.7119ZM15.2674 33.7119H11.3771V6.28124H15.2674V33.7119ZM8.15814 33.7119H5.375V6.28124H8.15814V33.7119Z" fill="currentColor"/>
 </svg>

+ 4 - 4
packages/ui/src/assets/icons/provider/io-net.svg

@@ -1,5 +1,5 @@
-<svg width="1000" height="1000" viewBox="0 0 1000 1000" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M77 394.324L166 454.625H77V679H166V454.625V320H77V394.324Z" fill="currentColor"/>
-<path d="M679.501 409.6C692.045 409.6 701.801 419.4 701.801 432V483.8L791 544V409.6C791 360.6 750.582 320 701.801 320H168L301.799 409.6H680.895H679.501Z" fill="currentColor"/>
-<path d="M411.499 589.4C398.955 589.4 389.199 579.6 389.199 567V515.2L300 455V589.4C300 638.4 340.418 679 389.199 679H923L789.201 589.4H410.105H411.499Z" fill="currentColor"/>
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M2.3999 9.60101L4.41977 10.9695H2.3999V16.0618H4.41977V10.9695V7.91422H2.3999V9.60101Z" fill="currentColor"/>
+<path d="M16.0739 9.9477C16.3586 9.9477 16.58 10.1701 16.58 10.4561V11.6317L18.6044 12.9979V9.9477C18.6044 8.83564 17.6871 7.91422 16.58 7.91422H4.46533L7.50191 9.9477H16.1055H16.0739Z" fill="currentColor"/>
+<path d="M9.99142 14.0283C9.70673 14.0283 9.48532 13.8059 9.48532 13.5199V12.3443L7.46094 10.9781V14.0283C7.46094 15.1403 8.37823 16.0618 9.48532 16.0618H21.6L18.5634 14.0283H9.95978H9.99142Z" fill="currentColor"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 0 - 2
packages/ui/src/assets/icons/provider/kimi-for-coding.svg


+ 2 - 6
packages/ui/src/assets/icons/provider/llama.svg

@@ -1,7 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
-  <!-- https://icones.js.org/collection/ri?s=meta&icon=ri:meta-fill -->
-  <path
-    fill="currentColor"
-    d="M16.92 4.5c-1.851 0-3.298 1.394-4.608 3.165C10.512 5.373 9.007 4.5 7.206 4.5C3.534 4.5.72 9.28.72 14.338c0 3.165 1.531 5.162 4.096 5.162c1.846 0 3.174-.87 5.535-4.997c0 0 .984-1.737 1.66-2.934q.356.574.75 1.238l1.107 1.862c2.156 3.608 3.358 4.831 5.534 4.831c2.5 0 3.89-2.024 3.89-5.255c0-5.297-2.877-9.745-6.372-9.745m-8.37 8.886c-1.913 3-2.575 3.673-3.64 3.673c-1.097 0-1.749-.963-1.749-2.68c0-3.672 1.831-7.427 4.014-7.427c1.182 0 2.17.682 3.683 2.848c-1.437 2.204-2.307 3.586-2.307 3.586m7.224-.377L14.45 10.8a45 45 0 0 0-1.032-1.608c1.193-1.841 2.176-2.759 3.347-2.759c2.43 0 4.375 3.58 4.375 7.976c0 1.676-.549 2.649-1.686 2.649c-1.09 0-1.61-.72-3.68-4.05"
-  />
+<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
+<path d="M27.1942 9.03509C24.4881 9.03509 22.3726 11.0731 20.4574 13.6623C17.8258 10.3114 15.6255 9.03509 12.9925 9.03509C7.62404 9.03509 3.51001 16.0234 3.51001 23.4181C3.51001 28.0453 5.74831 30.9649 9.49831 30.9649C12.1971 30.9649 14.1387 29.693 17.5904 23.6594C17.5904 23.6594 19.029 21.1199 20.0173 19.3699C20.3643 19.9293 20.7298 20.5327 21.1138 21.1798L22.7322 23.902C25.8843 29.1769 27.6416 30.9649 30.8229 30.9649C34.4778 30.9649 36.51 28.0058 36.51 23.2822C36.51 15.538 32.3039 9.03509 27.1942 9.03509ZM14.9574 22.0263C12.1606 26.4123 11.1928 27.3962 9.63574 27.3962C8.03194 27.3962 7.07872 25.9883 7.07872 23.4781C7.07872 18.1096 9.75562 12.6199 12.9471 12.6199C14.6752 12.6199 16.1197 13.617 18.3316 16.7836C16.2308 20.0058 14.9574 22.0263 14.9574 22.0263ZM25.5202 21.4751L23.5831 18.2456C23.0969 17.4514 22.5938 16.6676 22.0743 15.8947C23.8185 13.2032 25.2556 11.8611 26.9676 11.8611C30.5202 11.8611 33.3638 17.095 33.3638 23.5219C33.3638 25.9722 32.5612 27.3947 30.8989 27.3947C29.3053 27.3947 28.5451 26.3421 25.5188 21.4737" fill="currentColor"/>
 </svg>

Разница между файлами не показана из-за своего большого размера
+ 0 - 2
packages/ui/src/assets/icons/provider/lucidquery.svg


Некоторые файлы не были показаны из-за большого количества измененных файлов