diff --git a/.github/workflows/docs-update.yml b/.github/workflows/docs-update.yml
index 559e74176..11d6a9c82 100644
--- a/.github/workflows/docs-update.yml
+++ b/.github/workflows/docs-update.yml
@@ -2,9 +2,8 @@ name: Docs Update
on:
schedule:
- # Run every 4 hours
- - cron: "0 */4 * * *"
- workflow_dispatch: # Allow manual trigger for testing
+ - cron: "0 */12 * * *"
+ workflow_dispatch:
jobs:
update-docs:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 9e6b49339..ec98d7061 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -151,12 +151,12 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
- workspaces: packages/tauri/src-tauri
+ workspaces: packages/desktop/src-tauri
shared-key: ${{ matrix.settings.target }}
- name: Prepare
run: |
- cd packages/tauri
+ cd packages/desktop
bun ./scripts/prepare.ts
env:
OPENCODE_VERSION: ${{ needs.publish.outputs.version }}
@@ -191,7 +191,7 @@ jobs:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8
with:
- projectPath: packages/tauri
+ projectPath: packages/desktop
uploadWorkflowArtifacts: true
tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose
diff --git a/.opencode/skill/test-skill/SKILL.md b/.opencode/skill/test-skill/SKILL.md
new file mode 100644
index 000000000..3fef059f2
--- /dev/null
+++ b/.opencode/skill/test-skill/SKILL.md
@@ -0,0 +1,6 @@
+---
+name: test-skill
+description: use this when asked to test skill
+---
+
+woah this is a test skill
diff --git a/AGENTS.md b/AGENTS.md
index 5a95fc509..bbb2a96f2 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,31 +4,4 @@
## Tool Calling
-- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. Here is an example illustrating how to execute 3 parallel file reads in this chat environment:
-
-json
-{
-"recipient_name": "multi_tool_use.parallel",
-"parameters": {
-"tool_uses": [
-{
-"recipient_name": "functions.read",
-"parameters": {
-"filePath": "path/to/file.tsx"
-}
-},
-{
-"recipient_name": "functions.read",
-"parameters": {
-"filePath": "path/to/file.ts"
-}
-},
-{
-"recipient_name": "functions.read",
-"parameters": {
-"filePath": "path/to/file.md"
-}
-}
-]
-}
-}
+- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE.
diff --git a/bun.lock b/bun.lock
index 3e8ccfede..60a018c3d 100644
--- a/bun.lock
+++ b/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:*",
@@ -21,112 +28,9 @@
"turbo": "2.5.6",
},
},
- "packages/console/app": {
- "name": "@opencode-ai/console-app",
- "version": "1.0.186",
- "dependencies": {
- "@cloudflare/vite-plugin": "1.15.2",
- "@ibm/plex": "6.4.1",
- "@jsx-email/render": "1.1.1",
- "@kobalte/core": "catalog:",
- "@openauthjs/openauth": "catalog:",
- "@opencode-ai/console-core": "workspace:*",
- "@opencode-ai/console-mail": "workspace:*",
- "@opencode-ai/console-resource": "workspace:*",
- "@opencode-ai/ui": "workspace:*",
- "@solidjs/meta": "catalog:",
- "@solidjs/router": "catalog:",
- "@solidjs/start": "catalog:",
- "chart.js": "4.5.1",
- "nitro": "3.0.1-alpha.1",
- "solid-js": "catalog:",
- "vite": "catalog:",
- "zod": "catalog:",
- },
- "devDependencies": {
- "@typescript/native-preview": "catalog:",
- "typescript": "catalog:",
- "wrangler": "4.50.0",
- },
- },
- "packages/console/core": {
- "name": "@opencode-ai/console-core",
- "version": "1.0.186",
- "dependencies": {
- "@aws-sdk/client-sts": "3.782.0",
- "@jsx-email/render": "1.1.1",
- "@opencode-ai/console-mail": "workspace:*",
- "@opencode-ai/console-resource": "workspace:*",
- "@planetscale/database": "1.19.0",
- "aws4fetch": "1.0.20",
- "drizzle-orm": "0.41.0",
- "postgres": "3.4.7",
- "stripe": "18.0.0",
- "ulid": "catalog:",
- "zod": "catalog:",
- },
- "devDependencies": {
- "@cloudflare/workers-types": "catalog:",
- "@tsconfig/node22": "22.0.2",
- "@types/bun": "1.3.0",
- "@types/node": "catalog:",
- "@typescript/native-preview": "catalog:",
- "drizzle-kit": "0.30.5",
- "mysql2": "3.14.4",
- "typescript": "catalog:",
- },
- },
- "packages/console/function": {
- "name": "@opencode-ai/console-function",
- "version": "1.0.186",
- "dependencies": {
- "@ai-sdk/anthropic": "2.0.0",
- "@ai-sdk/openai": "2.0.2",
- "@ai-sdk/openai-compatible": "1.0.1",
- "@hono/zod-validator": "catalog:",
- "@openauthjs/openauth": "0.0.0-20250322224806",
- "@opencode-ai/console-core": "workspace:*",
- "@opencode-ai/console-resource": "workspace:*",
- "ai": "catalog:",
- "hono": "catalog:",
- "zod": "catalog:",
- },
- "devDependencies": {
- "@cloudflare/workers-types": "catalog:",
- "@tsconfig/node22": "22.0.2",
- "@types/node": "catalog:",
- "@typescript/native-preview": "catalog:",
- "openai": "5.11.0",
- "typescript": "catalog:",
- },
- },
- "packages/console/mail": {
- "name": "@opencode-ai/console-mail",
- "version": "1.0.186",
- "dependencies": {
- "@jsx-email/all": "2.2.3",
- "@jsx-email/cli": "1.4.3",
- "@tsconfig/bun": "1.0.9",
- "@types/react": "18.0.25",
- "react": "18.2.0",
- "solid-js": "catalog:",
- },
- },
- "packages/console/resource": {
- "name": "@opencode-ai/console-resource",
- "dependencies": {
- "@cloudflare/workers-types": "catalog:",
- },
- "devDependencies": {
- "@cloudflare/workers-types": "catalog:",
- "@tsconfig/node22": "22.0.2",
- "@types/node": "catalog:",
- "cloudflare": "5.2.0",
- },
- },
- "packages/desktop": {
- "name": "@opencode-ai/desktop",
- "version": "1.0.186",
+ "packages/app": {
+ "name": "@opencode-ai/app",
+ "version": "1.0.191",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -172,9 +76,139 @@
"vite-plugin-solid": "catalog:",
},
},
+ "packages/console/app": {
+ "name": "@opencode-ai/console-app",
+ "version": "1.0.191",
+ "dependencies": {
+ "@cloudflare/vite-plugin": "1.15.2",
+ "@ibm/plex": "6.4.1",
+ "@jsx-email/render": "1.1.1",
+ "@kobalte/core": "catalog:",
+ "@openauthjs/openauth": "catalog:",
+ "@opencode-ai/console-core": "workspace:*",
+ "@opencode-ai/console-mail": "workspace:*",
+ "@opencode-ai/console-resource": "workspace:*",
+ "@opencode-ai/ui": "workspace:*",
+ "@solidjs/meta": "catalog:",
+ "@solidjs/router": "catalog:",
+ "@solidjs/start": "catalog:",
+ "chart.js": "4.5.1",
+ "nitro": "3.0.1-alpha.1",
+ "solid-js": "catalog:",
+ "vite": "catalog:",
+ "zod": "catalog:",
+ },
+ "devDependencies": {
+ "@typescript/native-preview": "catalog:",
+ "typescript": "catalog:",
+ "wrangler": "4.50.0",
+ },
+ },
+ "packages/console/core": {
+ "name": "@opencode-ai/console-core",
+ "version": "1.0.191",
+ "dependencies": {
+ "@aws-sdk/client-sts": "3.782.0",
+ "@jsx-email/render": "1.1.1",
+ "@opencode-ai/console-mail": "workspace:*",
+ "@opencode-ai/console-resource": "workspace:*",
+ "@planetscale/database": "1.19.0",
+ "aws4fetch": "1.0.20",
+ "drizzle-orm": "0.41.0",
+ "postgres": "3.4.7",
+ "stripe": "18.0.0",
+ "ulid": "catalog:",
+ "zod": "catalog:",
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "catalog:",
+ "@tsconfig/node22": "22.0.2",
+ "@types/bun": "1.3.0",
+ "@types/node": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "drizzle-kit": "0.30.5",
+ "mysql2": "3.14.4",
+ "typescript": "catalog:",
+ },
+ },
+ "packages/console/function": {
+ "name": "@opencode-ai/console-function",
+ "version": "1.0.191",
+ "dependencies": {
+ "@ai-sdk/anthropic": "2.0.0",
+ "@ai-sdk/openai": "2.0.2",
+ "@ai-sdk/openai-compatible": "1.0.1",
+ "@hono/zod-validator": "catalog:",
+ "@openauthjs/openauth": "0.0.0-20250322224806",
+ "@opencode-ai/console-core": "workspace:*",
+ "@opencode-ai/console-resource": "workspace:*",
+ "ai": "catalog:",
+ "hono": "catalog:",
+ "zod": "catalog:",
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "catalog:",
+ "@tsconfig/node22": "22.0.2",
+ "@types/node": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "openai": "5.11.0",
+ "typescript": "catalog:",
+ },
+ },
+ "packages/console/mail": {
+ "name": "@opencode-ai/console-mail",
+ "version": "1.0.191",
+ "dependencies": {
+ "@jsx-email/all": "2.2.3",
+ "@jsx-email/cli": "1.4.3",
+ "@tsconfig/bun": "1.0.9",
+ "@types/react": "18.0.25",
+ "react": "18.2.0",
+ "solid-js": "catalog:",
+ },
+ },
+ "packages/console/resource": {
+ "name": "@opencode-ai/console-resource",
+ "dependencies": {
+ "@cloudflare/workers-types": "catalog:",
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "catalog:",
+ "@tsconfig/node22": "22.0.2",
+ "@types/node": "catalog:",
+ "cloudflare": "5.2.0",
+ },
+ },
+ "packages/desktop": {
+ "name": "@opencode-ai/desktop",
+ "version": "1.0.191",
+ "dependencies": {
+ "@opencode-ai/app": "workspace:*",
+ "@solid-primitives/storage": "catalog:",
+ "@tauri-apps/api": "^2",
+ "@tauri-apps/plugin-dialog": "~2",
+ "@tauri-apps/plugin-http": "~2",
+ "@tauri-apps/plugin-opener": "^2",
+ "@tauri-apps/plugin-os": "~2",
+ "@tauri-apps/plugin-process": "~2",
+ "@tauri-apps/plugin-shell": "~2",
+ "@tauri-apps/plugin-store": "~2",
+ "@tauri-apps/plugin-updater": "~2",
+ "@tauri-apps/plugin-window-state": "~2",
+ "solid-js": "catalog:",
+ },
+ "devDependencies": {
+ "@actions/artifact": "4.0.0",
+ "@tauri-apps/cli": "^2",
+ "@types/bun": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "typescript": "~5.6.2",
+ "vite": "catalog:",
+ },
+ },
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@opencode-ai/ui": "workspace:*",
"@opencode-ai/util": "workspace:*",
@@ -203,7 +237,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -219,7 +253,7 @@
},
"packages/opencode": {
"name": "opencode",
- "version": "1.0.186",
+ "version": "1.0.191",
"bin": {
"opencode": "./bin/opencode",
},
@@ -233,10 +267,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:",
@@ -249,8 +285,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",
@@ -311,7 +347,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -331,7 +367,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
- "version": "1.0.186",
+ "version": "1.0.191",
"devDependencies": {
"@hey-api/openapi-ts": "0.88.1",
"@tsconfig/node22": "catalog:",
@@ -342,7 +378,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -353,36 +389,9 @@
"typescript": "catalog:",
},
},
- "packages/tauri": {
- "name": "@opencode-ai/tauri",
- "version": "1.0.186",
- "dependencies": {
- "@opencode-ai/desktop": "workspace:*",
- "@solid-primitives/storage": "catalog:",
- "@tauri-apps/api": "^2",
- "@tauri-apps/plugin-dialog": "~2",
- "@tauri-apps/plugin-http": "~2",
- "@tauri-apps/plugin-opener": "^2",
- "@tauri-apps/plugin-os": "~2",
- "@tauri-apps/plugin-process": "~2",
- "@tauri-apps/plugin-shell": "~2",
- "@tauri-apps/plugin-store": "~2",
- "@tauri-apps/plugin-updater": "~2",
- "@tauri-apps/plugin-window-state": "~2",
- "solid-js": "catalog:",
- },
- "devDependencies": {
- "@actions/artifact": "4.0.0",
- "@tauri-apps/cli": "^2",
- "@types/bun": "catalog:",
- "@typescript/native-preview": "catalog:",
- "typescript": "~5.6.2",
- "vite": "catalog:",
- },
- },
"packages/ui": {
"name": "@opencode-ai/ui",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -417,7 +426,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"zod": "catalog:",
},
@@ -428,7 +437,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -447,7 +456,6 @@
"marked-shiki": "1.2.1",
"rehype-autolink-headings": "7.1.0",
"remeda": "catalog:",
- "sharp": "0.32.5",
"shiki": "3.4.2",
"solid-js": "catalog:",
"toolbeam-docs-theme": "0.4.8",
@@ -460,7 +468,6 @@
},
},
"trustedDependencies": [
- "sharp",
"esbuild",
"web-tree-sitter",
"tree-sitter-bash",
@@ -530,22 +537,38 @@
"@ai-sdk/azure": ["@ai-sdk/azure@2.0.73", "", { "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/gateway@2.0.12", "", { "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/cerebras@1.0.33", "", { "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/cohere@2.0.21", "", { "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/deepinfra@1.0.30", "", { "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/gateway@2.0.23", "", { "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/google@2.0.44", "", { "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/google-vertex@3.0.81", "", { "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/groq@2.0.33", "", { "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/mcp@0.0.8", "", { "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/mistral@2.0.26", "", { "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/openai@2.0.2", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-D4zYz2uR90aooKQvX1XnS00Z7PkbrcY+snUvPfm5bCabTG7bzLrVtD56nJ5bSaZG8lmuOMfXpyiEEArYLyWPpw=="],
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.1", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-luHVcU+yKzwv3ekKgbP3v+elUVxb2Rt+8c6w9qi7g2NYG2/pEL21oIrnaEnc6UtTZLLZX9EFBcpq2N1FQKDIMw=="],
+ "@ai-sdk/perplexity": ["@ai-sdk/perplexity@2.0.22", "", { "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/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="],
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.18", "", { "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/togetherai@1.0.30", "", { "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/xai@2.0.42", "", { "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/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
@@ -1126,6 +1149,8 @@
"@openauthjs/openauth": ["@openauthjs/openauth@0.0.0-20250322224806", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-p5IWSRXvABcwocH2dNI0w8c1QJelIOFulwhKk+aLLFfUbs8u1pr7kQbYe8yCSM2+bcLHiwbogpUQc2ovrGwCuw=="],
+ "@opencode-ai/app": ["@opencode-ai/app@workspace:packages/app"],
+
"@opencode-ai/console-app": ["@opencode-ai/console-app@workspace:packages/console/app"],
"@opencode-ai/console-core": ["@opencode-ai/console-core@workspace:packages/console/core"],
@@ -1150,8 +1175,6 @@
"@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"],
- "@opencode-ai/tauri": ["@opencode-ai/tauri@workspace:packages/tauri"],
-
"@opencode-ai/ui": ["@opencode-ai/ui@workspace:packages/ui"],
"@opencode-ai/util": ["@opencode-ai/util@workspace:packages/util"],
@@ -1164,19 +1187,19 @@
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
- "@opentui/core": ["@opentui/core@0.1.62", "", { "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/core@0.1.63", "", { "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/core-darwin-arm64@0.1.62", "", { "os": "darwin", "cpu": "arm64" }, "sha512-IohPhCkD/DbZEH4M5ft1/o1pI6Vvw2pdxdyoouW/TO1g21W5G8usaWTSRDXO+16BT115Nfb9/DT69H5pzAc2Eg=="],
+ "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.63", "", { "os": "darwin", "cpu": "arm64" }, "sha512-jKCThZGiiublKkP/hMtDtl1MLCw5NU0hMNJdEYvz1WLT9bzliWf6Kb7MIDAmk32XlbQW8/RHdp+hGyGDXK62OQ=="],
- "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.62", "", { "os": "darwin", "cpu": "x64" }, "sha512-BqbjQl2sLYrJ1Pq1b3H1I2CFedRiMz0QtZX08IMbyZ5kok+J0A8eQS5tmlbfqoS/VH0de9XiEbuHjG09/nSj1A=="],
+ "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.63", "", { "os": "darwin", "cpu": "x64" }, "sha512-rfNxynHzJpxN9i+SAMnn1NToEc8rYj64BsOxY78JNsm4Gg1Js1uyMaawwh2WbdGknFy4cDXS9QwkUMdMcfnjiw=="],
- "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.62", "", { "os": "linux", "cpu": "arm64" }, "sha512-P5FleF+W8O4uGubqBvV8DB1AK0+fJhJS8HvfmTZQ2DhSSJJH9Af/WXqitD7ILQY9ltlaUP7l38BC5cVdxnWzCQ=="],
+ "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.63", "", { "os": "linux", "cpu": "arm64" }, "sha512-wG9d6mHWWKZGrzxYS4c+BrcEGXBv/MYBUPSyjP/lD0CxT+X3h6CYhI317JkRyMNfh3vI9CpAKGFTOFvrTTHimQ=="],
- "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.62", "", { "os": "linux", "cpu": "x64" }, "sha512-l9ab5tgOGcdf8k3NU4TzK/3C8UC0+QuMxgLA/j60BhB1e9bwJleFeYJc+wLIktTUu9QwqCsU4YcuGHL+C2lCzA=="],
+ "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.63", "", { "os": "linux", "cpu": "x64" }, "sha512-TKSzFv4BgWW3RB/iZmq5qxTR4/tRaXo8IZNnVR+LFzShbPOqhUi466AByy9SUmCxD8uYjmMDFYfKtkCy0AnAwA=="],
- "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.62", "", { "os": "win32", "cpu": "arm64" }, "sha512-U1zsOpQl3EGhs8BwoehKAwwVONe+XOXRnXTxMhXw8huF0WWXDWOUL5psjBvfSWPm1rLmagxkQsH84jTSWA/vLA=="],
+ "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.63", "", { "os": "win32", "cpu": "arm64" }, "sha512-CBWPyPognERP0Mq4eC1q01Ado2C2WU+BLTgMdhyt+E2P4w8rPhJ2kCt2MNxO66vQUiynspmZkgjQr0II/VjxWA=="],
- "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.62", "", { "os": "win32", "cpu": "x64" }, "sha512-JgLZXSaE4q7gUIQb9x6fLWFF3BYlMod2VBhOT1qGBdeveZxsM6ZAno/g+CL9IDUydWfLFadOIBjdYFDVWV2Z2w=="],
+ "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.63", "", { "os": "win32", "cpu": "x64" }, "sha512-qEp6h//FrT+TQiiHm87wZWUwqTPTqIy1ZD+8R+VCUK+usoQiOAD2SqrYnM7W8JkCMGn5/TKm/GaKLyx/qlK4VA=="],
"@opentui/solid": ["@opentui/solid@0.1.63", "", { "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=="],
@@ -1952,16 +1975,6 @@
"bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="],
- "bare-fs": ["bare-fs@4.5.1", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4", "bare-url": "^2.2.2", "fast-fifo": "^1.3.2" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-zGUCsm3yv/ePt2PHNbVxjjn0nNB1MkIaR4wOCxJ2ig5pCf5cCVAYJXVhQg/3OhhJV6DB1ts7Hv0oUaElc2TPQg=="],
-
- "bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="],
-
- "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="],
-
- "bare-stream": ["bare-stream@2.7.0", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A=="],
-
- "bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="],
-
"base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
@@ -1980,8 +1993,6 @@
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
- "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
-
"blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="],
"blob-to-buffer": ["blob-to-buffer@1.2.9", "", {}, "sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA=="],
@@ -2058,7 +2069,7 @@
"chainsaw": ["chainsaw@0.1.0", "", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="],
- "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+ "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
@@ -2184,10 +2195,6 @@
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
- "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
-
- "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="],
-
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="],
@@ -2216,7 +2223,7 @@
"destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="],
- "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+ "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
@@ -2276,8 +2283,6 @@
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
- "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
-
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
@@ -2358,8 +2363,6 @@
"exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="],
- "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
-
"expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
"express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="],
@@ -2428,8 +2431,6 @@
"fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
- "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
-
"fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
@@ -2480,8 +2481,6 @@
"giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
- "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
-
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
"glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="],
@@ -3006,8 +3005,6 @@
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
- "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
-
"miniflare": ["miniflare@4.20251118.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251118.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ=="],
"minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
@@ -3020,8 +3017,6 @@
"mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
- "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
-
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
@@ -3036,8 +3031,6 @@
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
- "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="],
-
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
"neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
@@ -3050,9 +3043,7 @@
"no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="],
- "node-abi": ["node-abi@3.85.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg=="],
-
- "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="],
+ "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
@@ -3244,8 +3235,6 @@
"powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="],
- "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
-
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"pretty": ["pretty@2.0.0", "", { "dependencies": { "condense-newlines": "^0.2.1", "extend-shallow": "^2.0.1", "js-beautify": "^1.6.12" } }, "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w=="],
@@ -3268,8 +3257,6 @@
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
- "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
-
"punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="],
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
@@ -3286,8 +3273,6 @@
"raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="],
- "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
-
"rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
"react": ["react@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ=="],
@@ -3446,7 +3431,7 @@
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
- "sharp": ["sharp@0.32.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", "semver": "^7.5.4", "simple-get": "^4.0.1", "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" } }, "sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ=="],
+ "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
@@ -3470,10 +3455,6 @@
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
- "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="],
-
- "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="],
-
"simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="],
"simple-xml-to-json": ["simple-xml-to-json@1.2.3", "", {}, "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA=="],
@@ -3572,8 +3553,6 @@
"strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
- "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
-
"stripe": ["stripe@18.0.0", "", { "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" } }, "sha512-3Fs33IzKUby//9kCkCa1uRpinAoTvj6rJgQ2jrBEysoxEvfsclvXdna1amyEYbA2EKkjynuB4+L/kleCCaWTpA=="],
"strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="],
@@ -3600,8 +3579,6 @@
"tar": ["tar@7.5.2", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg=="],
- "tar-fs": ["tar-fs@3.1.1", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg=="],
-
"tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="],
"terracotta": ["terracotta@1.0.6", "", { "dependencies": { "solid-use": "^0.9.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-yVrmT/Lg6a3tEbeYEJH8ksb1PYkR5FA9k5gr1TchaSNIiA2ZWs5a+koEbePXwlBP0poaV7xViZ/v50bQFcMgqw=="],
@@ -3662,8 +3639,6 @@
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
- "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
-
"turbo": ["turbo@2.5.6", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.6", "turbo-darwin-arm64": "2.5.6", "turbo-linux-64": "2.5.6", "turbo-linux-arm64": "2.5.6", "turbo-windows-64": "2.5.6", "turbo-windows-arm64": "2.5.6" }, "bin": { "turbo": "bin/turbo" } }, "sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w=="],
"turbo-darwin-64": ["turbo-darwin-64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A=="],
@@ -3908,16 +3883,40 @@
"@ai-sdk/azure/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.17", "", { "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/provider-utils@3.0.17", "", { "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/openai-compatible@1.0.29", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+ "@ai-sdk/cerebras/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.19", "", { "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/provider-utils@3.0.19", "", { "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/openai-compatible@1.0.29", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+ "@ai-sdk/deepinfra/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.19", "", { "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/provider-utils@3.0.19", "", { "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/anthropic@2.0.50", "", { "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/provider-utils@3.0.19", "", { "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/provider-utils@3.0.17", "", { "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/provider-utils@3.0.19", "", { "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/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="],
"@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="],
+ "@ai-sdk/perplexity/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.19", "", { "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/openai-compatible@1.0.29", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+ "@ai-sdk/togetherai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.19", "", { "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/openai-compatible@1.0.29", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cZUppWzxjfpNaH1oVZ6U8yDLKKsdGbC9X0Pex8cG9CXhKWSoVLLnW1rKr6tu9jDISK5okjBIW/O1ZzfnbUrtEw=="],
+
+ "@ai-sdk/xai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.19", "", { "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": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
"@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="],
@@ -3984,6 +3983,8 @@
"@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
+ "@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"@expressive-code/plugin-shiki/shiki": ["shiki@3.15.0", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/engine-javascript": "3.15.0", "@shikijs/engine-oniguruma": "3.15.0", "@shikijs/langs": "3.15.0", "@shikijs/themes": "3.15.0", "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="],
@@ -4030,6 +4031,8 @@
"@jimp/types/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
+ "@jsx-email/cli/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+
"@jsx-email/cli/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
"@jsx-email/cli/tailwindcss": ["tailwindcss@3.3.3", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w=="],
@@ -4104,9 +4107,9 @@
"@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="],
- "@opencode-ai/tauri/@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=="],
+ "@opencode-ai/desktop/@actions/artifact": ["@actions/artifact@4.0.0", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="],
- "@opencode-ai/tauri/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
+ "@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
"@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="],
@@ -4120,10 +4123,6 @@
"@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="],
- "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
-
- "@parcel/watcher/node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
-
"@pierre/diffs/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="],
"@pierre/diffs/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-ZfWJNm2VMhKkQIKT9qXbs76RRcT0SF/CAvEz0+RkpUDAoDaCx0uFdCGzSRiD9gSlhm6AHkjdieOBJMaO2eC1rQ=="],
@@ -4162,6 +4161,8 @@
"@solidjs/start/vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="],
+ "@tailwindcss/oxide/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
@@ -4176,6 +4177,8 @@
"accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+ "ai/@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.12", "", { "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/provider-utils@3.0.17", "", { "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": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -4190,8 +4193,6 @@
"astro/diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="],
- "astro/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
-
"astro/shiki": ["shiki@3.15.0", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/engine-javascript": "3.15.0", "@shikijs/engine-oniguruma": "3.15.0", "@shikijs/langs": "3.15.0", "@shikijs/themes": "3.15.0", "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="],
"astro/unstorage": ["unstorage@1.17.3", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q=="],
@@ -4206,18 +4207,12 @@
"babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
- "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
-
- "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
-
"body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
"body-parser/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
- "boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
-
"clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
@@ -4236,6 +4231,8 @@
"es-get-iterator/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
+ "esbuild-plugin-copy/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+
"esbuild-plugin-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
@@ -4272,7 +4269,7 @@
"lazystream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
- "locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="],
+ "lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"md-to-react-email/marked": ["marked@7.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ=="],
@@ -4282,8 +4279,6 @@
"miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
- "miniflare/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
-
"miniflare/undici": ["undici@7.14.0", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="],
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
@@ -4332,8 +4327,6 @@
"postcss-load-config/lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
- "prebuild-install/tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="],
-
"prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
@@ -4354,6 +4347,8 @@
"send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
+ "sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+
"sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
@@ -4390,10 +4385,6 @@
"utif2/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
- "vite-plugin-icons-spritesheet/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
-
- "vite-plugin-solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="],
-
"vitest/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
"vitest/vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="],
@@ -4700,7 +4691,7 @@
"@octokit/rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
- "@opencode-ai/tauri/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
+ "@opencode-ai/desktop/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
"@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="],
@@ -4944,10 +4935,6 @@
"pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
- "prebuild-install/tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
-
- "prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
-
"readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
@@ -5078,7 +5065,7 @@
"@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
- "@opencode-ai/tauri/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
+ "@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
"@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
@@ -5132,8 +5119,6 @@
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
- "prebuild-install/tar-fs/tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
-
"tw-to-css/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"tw-to-css/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
diff --git a/infra/app.ts b/infra/app.ts
index 7215995ba..da4ac45b8 100644
--- a/infra/app.ts
+++ b/infra/app.ts
@@ -44,3 +44,12 @@ new sst.cloudflare.x.Astro("Web", {
VITE_API_URL: api.url.apply((url) => url!),
},
})
+
+new sst.cloudflare.StaticSite("App", {
+ domain: "app." + domain,
+ path: "packages/app",
+ build: {
+ command: "bun turbo build",
+ output: "./dist",
+ },
+})
diff --git a/infra/console.ts b/infra/console.ts
index 8f54823f8..0cc6a404b 100644
--- a/infra/console.ts
+++ b/infra/console.ts
@@ -118,6 +118,7 @@ const gatewayKv = new sst.cloudflare.Kv("GatewayKv")
////////////////
const bucket = new sst.cloudflare.Bucket("ZenData")
+const bucketNew = new sst.cloudflare.Bucket("ZenDataNew")
const AWS_SES_ACCESS_KEY_ID = new sst.Secret("AWS_SES_ACCESS_KEY_ID")
const AWS_SES_SECRET_ACCESS_KEY = new sst.Secret("AWS_SES_SECRET_ACCESS_KEY")
@@ -136,6 +137,7 @@ new sst.cloudflare.x.SolidStart("Console", {
path: "packages/console/app",
link: [
bucket,
+ bucketNew,
database,
AUTH_API_URL,
STRIPE_WEBHOOK_SECRET,
diff --git a/infra/desktop.ts b/infra/desktop.ts
index d4e32c65d..5c4155cc9 100644
--- a/infra/desktop.ts
+++ b/infra/desktop.ts
@@ -2,7 +2,7 @@ import { domain } from "./stage"
new sst.cloudflare.StaticSite("Desktop", {
domain: "desktop." + domain,
- path: "packages/desktop",
+ path: "packages/app",
build: {
command: "bun turbo build",
output: "./dist",
diff --git a/nix/hashes.json b/nix/hashes.json
index d56c40e9c..dbf753171 100644
--- a/nix/hashes.json
+++ b/nix/hashes.json
@@ -1,3 +1,3 @@
{
- "nodeModules": "sha256-0wqqGcWGlX8Zrqsf2M803hL63QQLjvJUy5bi9NhJTt4="
+ "nodeModules": "sha256-QlQblkUq49DOdvNNMNAzHHAfHxR6cZNmJtyzc4rD168="
}
diff --git a/package.json b/package.json
index fc8f1a4f1..3134cc976 100644
--- a/package.json
+++ b/package.json
@@ -64,11 +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:*",
- "@opentui/solid": "0.1.63",
"typescript": "catalog:"
},
"repository": {
@@ -83,7 +89,6 @@
"trustedDependencies": [
"esbuild",
"protobufjs",
- "sharp",
"tree-sitter",
"tree-sitter-bash",
"web-tree-sitter"
diff --git a/packages/app/.gitignore b/packages/app/.gitignore
new file mode 100644
index 000000000..4a20d55a7
--- /dev/null
+++ b/packages/app/.gitignore
@@ -0,0 +1 @@
+src/assets/theme.css
diff --git a/packages/desktop/AGENTS.md b/packages/app/AGENTS.md
similarity index 100%
rename from packages/desktop/AGENTS.md
rename to packages/app/AGENTS.md
diff --git a/packages/app/README.md b/packages/app/README.md
new file mode 100644
index 000000000..6a1764536
--- /dev/null
+++ b/packages/app/README.md
@@ -0,0 +1,34 @@
+## Usage
+
+Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
+
+This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
+
+```bash
+$ npm install # or pnpm install or yarn install
+```
+
+### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `npm run dev` or `npm start`
+
+Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
+
+The page will reload if you make edits.
+
+### `npm run build`
+
+Builds the app for production to the `dist` folder.
+It correctly bundles Solid in production mode and optimizes the build for the best performance.
+
+The build is minified and the filenames include the hashes.
+Your app is ready to be deployed!
+
+## Deployment
+
+You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)
diff --git a/packages/desktop/bunfig.toml b/packages/app/bunfig.toml
similarity index 100%
rename from packages/desktop/bunfig.toml
rename to packages/app/bunfig.toml
diff --git a/packages/desktop/happydom.ts b/packages/app/happydom.ts
similarity index 100%
rename from packages/desktop/happydom.ts
rename to packages/app/happydom.ts
diff --git a/packages/tauri/index.html b/packages/app/index.html
similarity index 88%
rename from packages/tauri/index.html
rename to packages/app/index.html
index faeb1a1fd..9803517a0 100644
--- a/packages/tauri/index.html
+++ b/packages/app/index.html
@@ -14,7 +14,7 @@
-
+
-
+
diff --git a/packages/app/package.json b/packages/app/package.json
new file mode 100644
index 000000000..404f8f11c
--- /dev/null
+++ b/packages/app/package.json
@@ -0,0 +1,62 @@
+{
+ "name": "@opencode-ai/app",
+ "version": "1.0.191",
+ "description": "",
+ "type": "module",
+ "exports": {
+ ".": "./src/index.ts",
+ "./vite": "./vite.js"
+ },
+ "scripts": {
+ "typecheck": "tsgo -b",
+ "start": "vite",
+ "dev": "vite",
+ "build": "vite build",
+ "serve": "vite preview"
+ },
+ "license": "MIT",
+ "devDependencies": {
+ "@happy-dom/global-registrator": "20.0.11",
+ "@tailwindcss/vite": "catalog:",
+ "@tsconfig/bun": "1.0.9",
+ "@types/bun": "catalog:",
+ "@types/luxon": "catalog:",
+ "@types/node": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "typescript": "catalog:",
+ "vite": "catalog:",
+ "vite-plugin-icons-spritesheet": "3.0.1",
+ "vite-plugin-solid": "catalog:"
+ },
+ "dependencies": {
+ "@kobalte/core": "catalog:",
+ "@opencode-ai/sdk": "workspace:*",
+ "@opencode-ai/ui": "workspace:*",
+ "@opencode-ai/util": "workspace:*",
+ "@shikijs/transformers": "3.9.2",
+ "@solid-primitives/active-element": "2.1.3",
+ "@solid-primitives/audio": "1.4.2",
+ "@solid-primitives/event-bus": "1.1.2",
+ "@solid-primitives/media": "2.3.3",
+ "@solid-primitives/resize-observer": "2.1.3",
+ "@solid-primitives/scroll": "2.1.3",
+ "@solid-primitives/storage": "catalog:",
+ "@solid-primitives/websocket": "1.3.1",
+ "@solidjs/meta": "catalog:",
+ "@solidjs/router": "catalog:",
+ "@thisbeyond/solid-dnd": "0.7.5",
+ "diff": "catalog:",
+ "fuzzysort": "catalog:",
+ "ghostty-web": "0.3.0",
+ "luxon": "catalog:",
+ "marked": "16.2.0",
+ "marked-shiki": "1.2.1",
+ "remeda": "catalog:",
+ "shiki": "3.9.2",
+ "solid-js": "catalog:",
+ "solid-list": "catalog:",
+ "tailwindcss": "catalog:",
+ "virtua": "catalog:",
+ "zod": "catalog:"
+ }
+}
diff --git a/packages/desktop/public/apple-touch-icon.png b/packages/app/public/apple-touch-icon.png
similarity index 100%
rename from packages/desktop/public/apple-touch-icon.png
rename to packages/app/public/apple-touch-icon.png
diff --git a/packages/desktop/public/favicon-96x96.png b/packages/app/public/favicon-96x96.png
similarity index 100%
rename from packages/desktop/public/favicon-96x96.png
rename to packages/app/public/favicon-96x96.png
diff --git a/packages/desktop/public/favicon.ico b/packages/app/public/favicon.ico
similarity index 100%
rename from packages/desktop/public/favicon.ico
rename to packages/app/public/favicon.ico
diff --git a/packages/desktop/public/favicon.svg b/packages/app/public/favicon.svg
similarity index 100%
rename from packages/desktop/public/favicon.svg
rename to packages/app/public/favicon.svg
diff --git a/packages/desktop/public/site.webmanifest b/packages/app/public/site.webmanifest
similarity index 100%
rename from packages/desktop/public/site.webmanifest
rename to packages/app/public/site.webmanifest
diff --git a/packages/desktop/public/social-share-zen.png b/packages/app/public/social-share-zen.png
similarity index 100%
rename from packages/desktop/public/social-share-zen.png
rename to packages/app/public/social-share-zen.png
diff --git a/packages/desktop/public/social-share.png b/packages/app/public/social-share.png
similarity index 100%
rename from packages/desktop/public/social-share.png
rename to packages/app/public/social-share.png
diff --git a/packages/desktop/public/web-app-manifest-192x192.png b/packages/app/public/web-app-manifest-192x192.png
similarity index 100%
rename from packages/desktop/public/web-app-manifest-192x192.png
rename to packages/app/public/web-app-manifest-192x192.png
diff --git a/packages/desktop/public/web-app-manifest-512x512.png b/packages/app/public/web-app-manifest-512x512.png
similarity index 100%
rename from packages/desktop/public/web-app-manifest-512x512.png
rename to packages/app/public/web-app-manifest-512x512.png
diff --git a/packages/desktop/src/addons/serialize.test.ts b/packages/app/src/addons/serialize.test.ts
similarity index 100%
rename from packages/desktop/src/addons/serialize.test.ts
rename to packages/app/src/addons/serialize.test.ts
diff --git a/packages/desktop/src/addons/serialize.ts b/packages/app/src/addons/serialize.ts
similarity index 100%
rename from packages/desktop/src/addons/serialize.ts
rename to packages/app/src/addons/serialize.ts
diff --git a/packages/desktop/src/app.tsx b/packages/app/src/app.tsx
similarity index 94%
rename from packages/desktop/src/app.tsx
rename to packages/app/src/app.tsx
index 9d000b8ff..11216643e 100644
--- a/packages/desktop/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -35,10 +35,10 @@ const url = iife(() => {
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"}`
+ if (import.meta.env.DEV)
+ return `http://${import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "localhost"}:${import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"}`
- return "/"
+ return "http://localhost:4096"
})
export function App() {
diff --git a/packages/desktop/src/components/dialog-connect-provider.tsx b/packages/app/src/components/dialog-connect-provider.tsx
similarity index 100%
rename from packages/desktop/src/components/dialog-connect-provider.tsx
rename to packages/app/src/components/dialog-connect-provider.tsx
diff --git a/packages/desktop/src/components/dialog-manage-models.tsx b/packages/app/src/components/dialog-manage-models.tsx
similarity index 100%
rename from packages/desktop/src/components/dialog-manage-models.tsx
rename to packages/app/src/components/dialog-manage-models.tsx
diff --git a/packages/desktop/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx
similarity index 100%
rename from packages/desktop/src/components/dialog-select-file.tsx
rename to packages/app/src/components/dialog-select-file.tsx
diff --git a/packages/desktop/src/components/dialog-select-model-unpaid.tsx b/packages/app/src/components/dialog-select-model-unpaid.tsx
similarity index 100%
rename from packages/desktop/src/components/dialog-select-model-unpaid.tsx
rename to packages/app/src/components/dialog-select-model-unpaid.tsx
diff --git a/packages/desktop/src/components/dialog-select-model.tsx b/packages/app/src/components/dialog-select-model.tsx
similarity index 100%
rename from packages/desktop/src/components/dialog-select-model.tsx
rename to packages/app/src/components/dialog-select-model.tsx
diff --git a/packages/desktop/src/components/dialog-select-provider.tsx b/packages/app/src/components/dialog-select-provider.tsx
similarity index 100%
rename from packages/desktop/src/components/dialog-select-provider.tsx
rename to packages/app/src/components/dialog-select-provider.tsx
diff --git a/packages/desktop/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx
similarity index 100%
rename from packages/desktop/src/components/file-tree.tsx
rename to packages/app/src/components/file-tree.tsx
diff --git a/packages/desktop/src/components/header.tsx b/packages/app/src/components/header.tsx
similarity index 84%
rename from packages/desktop/src/components/header.tsx
rename to packages/app/src/components/header.tsx
index c5ecd9871..ec7cdfa25 100644
--- a/packages/desktop/src/components/header.tsx
+++ b/packages/app/src/components/header.tsx
@@ -109,6 +109,35 @@ export function Header(props: {
+
+ Toggle review
+ {command.keybind("review.toggle")}
+
+ }
+ >
+
+
x.data)
+ if (!health?.healthy) {
+ setGlobalStore(
+ "error",
+ new Error(`Could not connect to server. Is there a server running at \`${globalSDK.url}\`?`),
+ )
+ return
+ }
+
return Promise.all([
retry(() =>
globalSDK.client.path.get().then((x) => {
diff --git a/packages/desktop/src/context/layout.tsx b/packages/app/src/context/layout.tsx
similarity index 95%
rename from packages/desktop/src/context/layout.tsx
rename to packages/app/src/context/layout.tsx
index 17cd4785c..c6ba5fef5 100644
--- a/packages/desktop/src/context/layout.tsx
+++ b/packages/app/src/context/layout.tsx
@@ -46,6 +46,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
opened: false,
height: 280,
},
+ review: {
+ opened: true,
+ },
session: {
width: 600,
},
@@ -158,6 +161,18 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
setStore("terminal", "height", height)
},
},
+ review: {
+ opened: createMemo(() => store.review?.opened ?? true),
+ open() {
+ setStore("review", "opened", true)
+ },
+ close() {
+ setStore("review", "opened", false)
+ },
+ toggle() {
+ setStore("review", "opened", (x) => !x)
+ },
+ },
session: {
width: createMemo(() => store.session?.width ?? 600),
resize(width: number) {
diff --git a/packages/desktop/src/context/local.tsx b/packages/app/src/context/local.tsx
similarity index 100%
rename from packages/desktop/src/context/local.tsx
rename to packages/app/src/context/local.tsx
diff --git a/packages/desktop/src/context/notification.tsx b/packages/app/src/context/notification.tsx
similarity index 100%
rename from packages/desktop/src/context/notification.tsx
rename to packages/app/src/context/notification.tsx
diff --git a/packages/desktop/src/context/platform.tsx b/packages/app/src/context/platform.tsx
similarity index 100%
rename from packages/desktop/src/context/platform.tsx
rename to packages/app/src/context/platform.tsx
diff --git a/packages/desktop/src/context/prompt.tsx b/packages/app/src/context/prompt.tsx
similarity index 100%
rename from packages/desktop/src/context/prompt.tsx
rename to packages/app/src/context/prompt.tsx
diff --git a/packages/desktop/src/context/sdk.tsx b/packages/app/src/context/sdk.tsx
similarity index 100%
rename from packages/desktop/src/context/sdk.tsx
rename to packages/app/src/context/sdk.tsx
diff --git a/packages/desktop/src/context/sync.tsx b/packages/app/src/context/sync.tsx
similarity index 100%
rename from packages/desktop/src/context/sync.tsx
rename to packages/app/src/context/sync.tsx
diff --git a/packages/desktop/src/context/terminal.tsx b/packages/app/src/context/terminal.tsx
similarity index 100%
rename from packages/desktop/src/context/terminal.tsx
rename to packages/app/src/context/terminal.tsx
diff --git a/packages/desktop/src/custom-elements.d.ts b/packages/app/src/custom-elements.d.ts
similarity index 100%
rename from packages/desktop/src/custom-elements.d.ts
rename to packages/app/src/custom-elements.d.ts
diff --git a/packages/desktop/src/entry.tsx b/packages/app/src/entry.tsx
similarity index 100%
rename from packages/desktop/src/entry.tsx
rename to packages/app/src/entry.tsx
diff --git a/packages/desktop/src/env.d.ts b/packages/app/src/env.d.ts
similarity index 100%
rename from packages/desktop/src/env.d.ts
rename to packages/app/src/env.d.ts
diff --git a/packages/desktop/src/hooks/use-providers.ts b/packages/app/src/hooks/use-providers.ts
similarity index 100%
rename from packages/desktop/src/hooks/use-providers.ts
rename to packages/app/src/hooks/use-providers.ts
diff --git a/packages/desktop/src/index.css b/packages/app/src/index.css
similarity index 100%
rename from packages/desktop/src/index.css
rename to packages/app/src/index.css
diff --git a/packages/desktop/src/index.ts b/packages/app/src/index.ts
similarity index 100%
rename from packages/desktop/src/index.ts
rename to packages/app/src/index.ts
diff --git a/packages/desktop/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx
similarity index 100%
rename from packages/desktop/src/pages/directory-layout.tsx
rename to packages/app/src/pages/directory-layout.tsx
diff --git a/packages/desktop/src/pages/error.tsx b/packages/app/src/pages/error.tsx
similarity index 78%
rename from packages/desktop/src/pages/error.tsx
rename to packages/app/src/pages/error.tsx
index c7330c298..9914279ad 100644
--- a/packages/desktop/src/pages/error.tsx
+++ b/packages/app/src/pages/error.tsx
@@ -62,27 +62,49 @@ function formatInitError(error: InitError): string {
}
}
-function formatErrorChain(error: unknown, depth = 0): string {
+function formatErrorChain(error: unknown, depth = 0, parentMessage?: string): string {
if (!error) return "Unknown error"
- const indent = depth > 0 ? `\n${"─".repeat(40)}\nCaused by:\n` : ""
-
if (isInitError(error)) {
- return indent + formatInitError(error)
+ const message = formatInitError(error)
+ if (depth > 0 && parentMessage === message) return ""
+ const indent = depth > 0 ? `\n${"─".repeat(40)}\nCaused by:\n` : ""
+ return indent + message
}
if (error instanceof Error) {
- const parts = [indent + `${error.name}: ${error.message}`]
- if (error.stack) {
- parts.push(error.stack)
+ const isDuplicate = depth > 0 && parentMessage === error.message
+ const parts: string[] = []
+ const indent = depth > 0 ? `\n${"─".repeat(40)}\nCaused by:\n` : ""
+
+ if (!isDuplicate) {
+ // Stack already includes error name and message, so prefer it
+ parts.push(indent + (error.stack ?? `${error.name}: ${error.message}`))
+ } else if (error.stack) {
+ // Duplicate message - only show the stack trace lines (skip message)
+ const trace = error.stack.split("\n").slice(1).join("\n").trim()
+ if (trace) {
+ parts.push(trace)
+ }
}
+
if (error.cause) {
- parts.push(formatErrorChain(error.cause, depth + 1))
+ const causeResult = formatErrorChain(error.cause, depth + 1, error.message)
+ if (causeResult) {
+ parts.push(causeResult)
+ }
}
+
return parts.join("\n\n")
}
- if (typeof error === "string") return indent + error
+ if (typeof error === "string") {
+ if (depth > 0 && parentMessage === error) return ""
+ const indent = depth > 0 ? `\n${"─".repeat(40)}\nCaused by:\n` : ""
+ return indent + error
+ }
+
+ const indent = depth > 0 ? `\n${"─".repeat(40)}\nCaused by:\n` : ""
return indent + JSON.stringify(error, null, 2)
}
diff --git a/packages/desktop/src/pages/home.tsx b/packages/app/src/pages/home.tsx
similarity index 100%
rename from packages/desktop/src/pages/home.tsx
rename to packages/app/src/pages/home.tsx
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
similarity index 100%
rename from packages/desktop/src/pages/layout.tsx
rename to packages/app/src/pages/layout.tsx
diff --git a/packages/desktop/src/pages/session.tsx b/packages/app/src/pages/session.tsx
similarity index 98%
rename from packages/desktop/src/pages/session.tsx
rename to packages/app/src/pages/session.tsx
index b6f5ccca1..42e43232a 100644
--- a/packages/desktop/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -221,6 +221,15 @@ export default function Page() {
slash: "terminal",
onSelect: () => layout.terminal.toggle(),
},
+ {
+ id: "review.toggle",
+ title: "Toggle review",
+ description: "Show or hide the review panel",
+ category: "View",
+ keybind: "mod+b",
+ slash: "review",
+ onSelect: () => layout.review.toggle(),
+ },
{
id: "terminal.new",
title: "New terminal",
@@ -533,7 +542,7 @@ export default function Page() {
)
}
- const showTabs = createMemo(() => diffs().length > 0 || tabs().all().length > 0)
+ const showTabs = createMemo(() => layout.review.opened() && (diffs().length > 0 || tabs().all().length > 0))
const mobileWorking = createMemo(() => status().type !== "idle")
const mobileAutoScroll = createAutoScroll({
diff --git a/packages/desktop/src/sst-env.d.ts b/packages/app/src/sst-env.d.ts
similarity index 100%
rename from packages/desktop/src/sst-env.d.ts
rename to packages/app/src/sst-env.d.ts
diff --git a/packages/desktop/src/utils/dom.ts b/packages/app/src/utils/dom.ts
similarity index 100%
rename from packages/desktop/src/utils/dom.ts
rename to packages/app/src/utils/dom.ts
diff --git a/packages/desktop/src/utils/id.ts b/packages/app/src/utils/id.ts
similarity index 100%
rename from packages/desktop/src/utils/id.ts
rename to packages/app/src/utils/id.ts
diff --git a/packages/desktop/src/utils/index.ts b/packages/app/src/utils/index.ts
similarity index 100%
rename from packages/desktop/src/utils/index.ts
rename to packages/app/src/utils/index.ts
diff --git a/packages/desktop/src/utils/persist.ts b/packages/app/src/utils/persist.ts
similarity index 100%
rename from packages/desktop/src/utils/persist.ts
rename to packages/app/src/utils/persist.ts
diff --git a/packages/desktop/src/utils/prompt.ts b/packages/app/src/utils/prompt.ts
similarity index 100%
rename from packages/desktop/src/utils/prompt.ts
rename to packages/app/src/utils/prompt.ts
diff --git a/packages/desktop/src/utils/solid-dnd.tsx b/packages/app/src/utils/solid-dnd.tsx
similarity index 100%
rename from packages/desktop/src/utils/solid-dnd.tsx
rename to packages/app/src/utils/solid-dnd.tsx
diff --git a/packages/desktop/src/utils/speech.ts b/packages/app/src/utils/speech.ts
similarity index 100%
rename from packages/desktop/src/utils/speech.ts
rename to packages/app/src/utils/speech.ts
diff --git a/packages/tauri/sst-env.d.ts b/packages/app/sst-env.d.ts
similarity index 100%
rename from packages/tauri/sst-env.d.ts
rename to packages/app/sst-env.d.ts
diff --git a/packages/tauri/tsconfig.json b/packages/app/tsconfig.json
similarity index 57%
rename from packages/tauri/tsconfig.json
rename to packages/app/tsconfig.json
index e7f5c5c27..db04f79ca 100644
--- a/packages/tauri/tsconfig.json
+++ b/packages/app/tsconfig.json
@@ -1,5 +1,7 @@
{
+ "$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
+ "composite": true,
"target": "ESNext",
"module": "ESNext",
"skipLibCheck": true,
@@ -10,11 +12,13 @@
"jsxImportSource": "solid-js",
"allowJs": true,
"strict": true,
+ "noEmit": false,
+ "emitDeclarationOnly": true,
+ "outDir": "node_modules/.ts-dist",
"isolatedModules": true,
- "noEmit": true,
- "emitDeclarationOnly": false,
- "outDir": "node_modules/.ts-dist"
+ "paths": {
+ "@/*": ["./src/*"]
+ }
},
- "references": [{ "path": "../desktop" }],
- "include": ["src"]
+ "exclude": ["dist", "ts-dist"]
}
diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts
new file mode 100644
index 000000000..57071a894
--- /dev/null
+++ b/packages/app/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from "vite"
+import desktopPlugin from "./vite"
+
+export default defineConfig({
+ plugins: [desktopPlugin] as any,
+ server: {
+ host: "0.0.0.0",
+ allowedHosts: true,
+ port: 3000,
+ },
+ build: {
+ target: "esnext",
+ sourcemap: true,
+ },
+})
diff --git a/packages/desktop/vite.js b/packages/app/vite.js
similarity index 100%
rename from packages/desktop/vite.js
rename to packages/app/vite.js
diff --git a/packages/console/app/package.json b/packages/console/app/package.json
index 2fe98264a..f22d54b8a 100644
--- a/packages/console/app/package.json
+++ b/packages/console/app/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
- "version": "1.0.186",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
diff --git a/packages/console/app/src/config.ts b/packages/console/app/src/config.ts
index 29df86cbd..bf20681ae 100644
--- a/packages/console/app/src/config.ts
+++ b/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
diff --git a/packages/console/app/src/routes/download/[platform].ts b/packages/console/app/src/routes/download/[platform].ts
index 486b6bf6c..427fb132b 100644
--- a/packages/console/app/src/routes/download/[platform].ts
+++ b/packages/console/app/src/routes/download/[platform].ts
@@ -6,6 +6,7 @@ const assetNames: Record = {
"darwin-x64-dmg": "opencode-desktop-darwin-x64.dmg",
"windows-x64-nsis": "opencode-desktop-windows-x64.exe",
"linux-x64-deb": "opencode-desktop-linux-amd64.deb",
+ "linux-x64-appimage": "opencode-desktop-linux-amd64.AppImage",
"linux-x64-rpm": "opencode-desktop-linux-x86_64.rpm",
} satisfies Record
diff --git a/packages/console/app/src/routes/download/index.tsx b/packages/console/app/src/routes/download/index.tsx
index 4f4258755..d4de97c68 100644
--- a/packages/console/app/src/routes/download/index.tsx
+++ b/packages/console/app/src/routes/download/index.tsx
@@ -244,6 +244,22 @@ export default function Download() {
Download
+
diff --git a/packages/console/app/src/routes/download/types.ts b/packages/console/app/src/routes/download/types.ts
index adf71880d..916f97022 100644
--- a/packages/console/app/src/routes/download/types.ts
+++ b/packages/console/app/src/routes/download/types.ts
@@ -1 +1,4 @@
-export type DownloadPlatform = `darwin-${"x64" | "aarch64"}-dmg` | "windows-x64-nsis" | `linux-x64-${"deb" | "rpm"}`
+export type DownloadPlatform =
+ | `darwin-${"x64" | "aarch64"}-dmg`
+ | "windows-x64-nsis"
+ | `linux-x64-${"deb" | "rpm" | "appimage"}`
diff --git a/packages/console/app/src/routes/zen/util/dataDumper.ts b/packages/console/app/src/routes/zen/util/dataDumper.ts
index 155cc6c58..b852ca0b5 100644
--- a/packages/console/app/src/routes/zen/util/dataDumper.ts
+++ b/packages/console/app/src/routes/zen/util/dataDumper.ts
@@ -19,17 +19,23 @@ export function createDataDumper(sessionId: string, requestId: string, projectId
if (!data.modelName) return
const timestamp = new Date().toISOString().replace(/[^0-9]/g, "")
+ const year = timestamp.substring(0, 4)
+ const month = timestamp.substring(4, 6)
+ const day = timestamp.substring(6, 8)
+ const hour = timestamp.substring(8, 10)
+ const minute = timestamp.substring(10, 12)
+ const second = timestamp.substring(12, 14)
waitUntil(
- Resource.ZenData.put(
- `data/${data.modelName}/${sessionId}/${requestId}.json`,
+ Resource.ZenDataNew.put(
+ `data/${data.modelName}/${year}/${month}/${day}/${hour}/${minute}/${second}/${requestId}.json`,
JSON.stringify({ timestamp, ...data }),
),
)
waitUntil(
- Resource.ZenData.put(
- `meta/${data.modelName}/${timestamp}/${requestId}.json`,
+ Resource.ZenDataNew.put(
+ `meta/${data.modelName}/${sessionId}/${requestId}.json`,
JSON.stringify({ timestamp, ...metadata }),
),
)
diff --git a/packages/console/core/package.json b/packages/console/core/package.json
index e1971f3ef..6ffedab0a 100644
--- a/packages/console/core/package.json
+++ b/packages/console/core/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
- "version": "1.0.186",
+ "version": "1.0.191",
"private": true,
"type": "module",
"dependencies": {
diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts
index 632ea3fbe..ffa17f276 100644
--- a/packages/console/core/sst-env.d.ts
+++ b/packages/console/core/sst-env.d.ts
@@ -132,6 +132,7 @@ declare module "sst" {
"GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
"ZenData": cloudflare.R2Bucket
+ "ZenDataNew": cloudflare.R2Bucket
}
}
diff --git a/packages/console/function/package.json b/packages/console/function/package.json
index 8c9daf340..95fc0e474 100644
--- a/packages/console/function/package.json
+++ b/packages/console/function/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
- "version": "1.0.186",
+ "version": "1.0.191",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts
index 632ea3fbe..ffa17f276 100644
--- a/packages/console/function/sst-env.d.ts
+++ b/packages/console/function/sst-env.d.ts
@@ -132,6 +132,7 @@ declare module "sst" {
"GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
"ZenData": cloudflare.R2Bucket
+ "ZenDataNew": cloudflare.R2Bucket
}
}
diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json
index 2ce541a3b..ff6b3f102 100644
--- a/packages/console/mail/package.json
+++ b/packages/console/mail/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
- "version": "1.0.186",
+ "version": "1.0.191",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts
index 632ea3fbe..ffa17f276 100644
--- a/packages/console/resource/sst-env.d.ts
+++ b/packages/console/resource/sst-env.d.ts
@@ -132,6 +132,7 @@ declare module "sst" {
"GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
"ZenData": cloudflare.R2Bucket
+ "ZenDataNew": cloudflare.R2Bucket
}
}
diff --git a/packages/desktop/.gitignore b/packages/desktop/.gitignore
index 4a20d55a7..a547bf36d 100644
--- a/packages/desktop/.gitignore
+++ b/packages/desktop/.gitignore
@@ -1 +1,24 @@
-src/assets/theme.css
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/packages/desktop/README.md b/packages/desktop/README.md
index 6a1764536..b381dcf5b 100644
--- a/packages/desktop/README.md
+++ b/packages/desktop/README.md
@@ -1,34 +1,7 @@
-## Usage
+# Tauri + Vanilla TS
-Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
+This template should help get you started developing with Tauri in vanilla HTML, CSS and Typescript.
-This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
+## Recommended IDE Setup
-```bash
-$ npm install # or pnpm install or yarn install
-```
-
-### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
-
-## Available Scripts
-
-In the project directory, you can run:
-
-### `npm run dev` or `npm start`
-
-Runs the app in the development mode.
-Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
-
-The page will reload if you make edits.
-
-### `npm run build`
-
-Builds the app for production to the `dist` folder.
-It correctly bundles Solid in production mode and optimizes the build for the best performance.
-
-The build is minified and the filenames include the hashes.
-Your app is ready to be deployed!
-
-## Deployment
-
-You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)
+- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
diff --git a/packages/desktop/index.html b/packages/desktop/index.html
index 9803517a0..faeb1a1fd 100644
--- a/packages/desktop/index.html
+++ b/packages/desktop/index.html
@@ -14,7 +14,7 @@
-
+
-
+
diff --git a/packages/desktop/package.json b/packages/desktop/package.json
index 5f38ac60d..23eab7f4d 100644
--- a/packages/desktop/package.json
+++ b/packages/desktop/package.json
@@ -1,62 +1,37 @@
{
"name": "@opencode-ai/desktop",
- "version": "1.0.186",
- "description": "",
+ "private": true,
+ "version": "1.0.191",
"type": "module",
- "exports": {
- ".": "./src/index.ts",
- "./vite": "./vite.js"
- },
"scripts": {
"typecheck": "tsgo -b",
- "start": "vite",
+ "predev": "bun ./scripts/predev.ts",
"dev": "vite",
- "build": "vite build",
- "serve": "vite preview"
- },
- "license": "MIT",
- "devDependencies": {
- "@happy-dom/global-registrator": "20.0.11",
- "@tailwindcss/vite": "catalog:",
- "@tsconfig/bun": "1.0.9",
- "@types/bun": "catalog:",
- "@types/luxon": "catalog:",
- "@types/node": "catalog:",
- "@typescript/native-preview": "catalog:",
- "typescript": "catalog:",
- "vite": "catalog:",
- "vite-plugin-icons-spritesheet": "3.0.1",
- "vite-plugin-solid": "catalog:"
+ "build": "bun run typecheck && vite build",
+ "preview": "vite preview",
+ "tauri": "tauri"
},
"dependencies": {
- "@kobalte/core": "catalog:",
- "@opencode-ai/sdk": "workspace:*",
- "@opencode-ai/ui": "workspace:*",
- "@opencode-ai/util": "workspace:*",
- "@shikijs/transformers": "3.9.2",
- "@solid-primitives/active-element": "2.1.3",
- "@solid-primitives/audio": "1.4.2",
- "@solid-primitives/event-bus": "1.1.2",
- "@solid-primitives/media": "2.3.3",
- "@solid-primitives/resize-observer": "2.1.3",
- "@solid-primitives/scroll": "2.1.3",
+ "@opencode-ai/app": "workspace:*",
"@solid-primitives/storage": "catalog:",
- "@solid-primitives/websocket": "1.3.1",
- "@solidjs/meta": "catalog:",
- "@solidjs/router": "catalog:",
- "@thisbeyond/solid-dnd": "0.7.5",
- "diff": "catalog:",
- "fuzzysort": "catalog:",
- "ghostty-web": "0.3.0",
- "luxon": "catalog:",
- "marked": "16.2.0",
- "marked-shiki": "1.2.1",
- "remeda": "catalog:",
- "shiki": "3.9.2",
- "solid-js": "catalog:",
- "solid-list": "catalog:",
- "tailwindcss": "catalog:",
- "virtua": "catalog:",
- "zod": "catalog:"
+ "@tauri-apps/api": "^2",
+ "@tauri-apps/plugin-dialog": "~2",
+ "@tauri-apps/plugin-opener": "^2",
+ "@tauri-apps/plugin-os": "~2",
+ "@tauri-apps/plugin-process": "~2",
+ "@tauri-apps/plugin-shell": "~2",
+ "@tauri-apps/plugin-store": "~2",
+ "@tauri-apps/plugin-updater": "~2",
+ "@tauri-apps/plugin-http": "~2",
+ "@tauri-apps/plugin-window-state": "~2",
+ "solid-js": "catalog:"
+ },
+ "devDependencies": {
+ "@actions/artifact": "4.0.0",
+ "@tauri-apps/cli": "^2",
+ "@types/bun": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "typescript": "~5.6.2",
+ "vite": "catalog:"
}
}
diff --git a/packages/tauri/scripts/copy-bundles.ts b/packages/desktop/scripts/copy-bundles.ts
similarity index 100%
rename from packages/tauri/scripts/copy-bundles.ts
rename to packages/desktop/scripts/copy-bundles.ts
diff --git a/packages/tauri/scripts/predev.ts b/packages/desktop/scripts/predev.ts
similarity index 100%
rename from packages/tauri/scripts/predev.ts
rename to packages/desktop/scripts/predev.ts
diff --git a/packages/tauri/scripts/prepare.ts b/packages/desktop/scripts/prepare.ts
similarity index 100%
rename from packages/tauri/scripts/prepare.ts
rename to packages/desktop/scripts/prepare.ts
diff --git a/packages/tauri/scripts/utils.ts b/packages/desktop/scripts/utils.ts
similarity index 100%
rename from packages/tauri/scripts/utils.ts
rename to packages/desktop/scripts/utils.ts
diff --git a/packages/tauri/src-tauri/.gitignore b/packages/desktop/src-tauri/.gitignore
similarity index 100%
rename from packages/tauri/src-tauri/.gitignore
rename to packages/desktop/src-tauri/.gitignore
diff --git a/packages/tauri/src-tauri/Cargo.lock b/packages/desktop/src-tauri/Cargo.lock
similarity index 100%
rename from packages/tauri/src-tauri/Cargo.lock
rename to packages/desktop/src-tauri/Cargo.lock
diff --git a/packages/tauri/src-tauri/Cargo.toml b/packages/desktop/src-tauri/Cargo.toml
similarity index 92%
rename from packages/tauri/src-tauri/Cargo.toml
rename to packages/desktop/src-tauri/Cargo.toml
index c6208190b..0463966c0 100644
--- a/packages/tauri/src-tauri/Cargo.toml
+++ b/packages/desktop/src-tauri/Cargo.toml
@@ -1,8 +1,8 @@
[package]
name = "opencode-desktop"
version = "0.0.0"
-description = "A Tauri App"
-authors = ["you"]
+description = "The open source AI coding agent"
+authors = ["Anomaly Innovations"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/packages/tauri/src-tauri/assets/nsis-header.bmp b/packages/desktop/src-tauri/assets/nsis-header.bmp
similarity index 100%
rename from packages/tauri/src-tauri/assets/nsis-header.bmp
rename to packages/desktop/src-tauri/assets/nsis-header.bmp
diff --git a/packages/tauri/src-tauri/assets/nsis-sidebar.bmp b/packages/desktop/src-tauri/assets/nsis-sidebar.bmp
similarity index 100%
rename from packages/tauri/src-tauri/assets/nsis-sidebar.bmp
rename to packages/desktop/src-tauri/assets/nsis-sidebar.bmp
diff --git a/packages/tauri/src-tauri/build.rs b/packages/desktop/src-tauri/build.rs
similarity index 100%
rename from packages/tauri/src-tauri/build.rs
rename to packages/desktop/src-tauri/build.rs
diff --git a/packages/tauri/src-tauri/capabilities/default.json b/packages/desktop/src-tauri/capabilities/default.json
similarity index 100%
rename from packages/tauri/src-tauri/capabilities/default.json
rename to packages/desktop/src-tauri/capabilities/default.json
diff --git a/packages/tauri/src-tauri/entitlements.plist b/packages/desktop/src-tauri/entitlements.plist
similarity index 100%
rename from packages/tauri/src-tauri/entitlements.plist
rename to packages/desktop/src-tauri/entitlements.plist
diff --git a/packages/tauri/src-tauri/icons/README.md b/packages/desktop/src-tauri/icons/README.md
similarity index 88%
rename from packages/tauri/src-tauri/icons/README.md
rename to packages/desktop/src-tauri/icons/README.md
index d4a4e687d..db86593cc 100644
--- a/packages/tauri/src-tauri/icons/README.md
+++ b/packages/desktop/src-tauri/icons/README.md
@@ -2,7 +2,7 @@
Here's the process I've been using to create icons:
-- Save source image as `app-icon.png` in `packages/tauri`
+- Save source image as `app-icon.png` in `packages/desktop`
- `cd` to `src-tauri`
- Run `bun tauri icons -o icons/{environment}`
- Use [Image2Icon](https://img2icnsapp.com/)'s 'Big Sur Icon' preset to generate an `icon.icns` file and place it in the appropriate icons folder
diff --git a/packages/tauri/src-tauri/icons/dev/128x128.png b/packages/desktop/src-tauri/icons/dev/128x128.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/128x128.png
rename to packages/desktop/src-tauri/icons/dev/128x128.png
diff --git a/packages/tauri/src-tauri/icons/dev/128x128@2x.png b/packages/desktop/src-tauri/icons/dev/128x128@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/128x128@2x.png
rename to packages/desktop/src-tauri/icons/dev/128x128@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/32x32.png b/packages/desktop/src-tauri/icons/dev/32x32.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/32x32.png
rename to packages/desktop/src-tauri/icons/dev/32x32.png
diff --git a/packages/tauri/src-tauri/icons/dev/64x64.png b/packages/desktop/src-tauri/icons/dev/64x64.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/64x64.png
rename to packages/desktop/src-tauri/icons/dev/64x64.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square107x107Logo.png b/packages/desktop/src-tauri/icons/dev/Square107x107Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square107x107Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square107x107Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square142x142Logo.png b/packages/desktop/src-tauri/icons/dev/Square142x142Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square142x142Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square142x142Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square150x150Logo.png b/packages/desktop/src-tauri/icons/dev/Square150x150Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square150x150Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square150x150Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square284x284Logo.png b/packages/desktop/src-tauri/icons/dev/Square284x284Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square284x284Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square284x284Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square30x30Logo.png b/packages/desktop/src-tauri/icons/dev/Square30x30Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square30x30Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square30x30Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square310x310Logo.png b/packages/desktop/src-tauri/icons/dev/Square310x310Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square310x310Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square310x310Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square44x44Logo.png b/packages/desktop/src-tauri/icons/dev/Square44x44Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square44x44Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square44x44Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square71x71Logo.png b/packages/desktop/src-tauri/icons/dev/Square71x71Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square71x71Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square71x71Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/Square89x89Logo.png b/packages/desktop/src-tauri/icons/dev/Square89x89Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/Square89x89Logo.png
rename to packages/desktop/src-tauri/icons/dev/Square89x89Logo.png
diff --git a/packages/tauri/src-tauri/icons/dev/StoreLogo.png b/packages/desktop/src-tauri/icons/dev/StoreLogo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/StoreLogo.png
rename to packages/desktop/src-tauri/icons/dev/StoreLogo.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml b/packages/desktop/src-tauri/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-hdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-mdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/dev/android/values/ic_launcher_background.xml b/packages/desktop/src-tauri/icons/dev/android/values/ic_launcher_background.xml
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/android/values/ic_launcher_background.xml
rename to packages/desktop/src-tauri/icons/dev/android/values/ic_launcher_background.xml
diff --git a/packages/tauri/src-tauri/icons/dev/icon.icns b/packages/desktop/src-tauri/icons/dev/icon.icns
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/icon.icns
rename to packages/desktop/src-tauri/icons/dev/icon.icns
diff --git a/packages/tauri/src-tauri/icons/dev/icon.ico b/packages/desktop/src-tauri/icons/dev/icon.ico
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/icon.ico
rename to packages/desktop/src-tauri/icons/dev/icon.ico
diff --git a/packages/tauri/src-tauri/icons/dev/icon.png b/packages/desktop/src-tauri/icons/dev/icon.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/icon.png
rename to packages/desktop/src-tauri/icons/dev/icon.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@1x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@1x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@1x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@2x-1.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@2x-1.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@2x-1.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@2x-1.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@3x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-20x20@3x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-20x20@3x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@1x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@1x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@1x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@2x-1.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@2x-1.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@2x-1.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@2x-1.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@3x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-29x29@3x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-29x29@3x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@1x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@1x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@1x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@2x-1.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@2x-1.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@2x-1.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@2x-1.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@3x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-40x40@3x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-40x40@3x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-512@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-512@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-512@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-512@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-60x60@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-60x60@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-60x60@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-60x60@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-60x60@3x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-60x60@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-60x60@3x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-60x60@3x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-76x76@1x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-76x76@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-76x76@1x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-76x76@1x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-76x76@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-76x76@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-76x76@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-76x76@2x.png
diff --git a/packages/tauri/src-tauri/icons/dev/ios/AppIcon-83.5x83.5@2x.png b/packages/desktop/src-tauri/icons/dev/ios/AppIcon-83.5x83.5@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/dev/ios/AppIcon-83.5x83.5@2x.png
rename to packages/desktop/src-tauri/icons/dev/ios/AppIcon-83.5x83.5@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/128x128.png b/packages/desktop/src-tauri/icons/prod/128x128.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/128x128.png
rename to packages/desktop/src-tauri/icons/prod/128x128.png
diff --git a/packages/tauri/src-tauri/icons/prod/128x128@2x.png b/packages/desktop/src-tauri/icons/prod/128x128@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/128x128@2x.png
rename to packages/desktop/src-tauri/icons/prod/128x128@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/32x32.png b/packages/desktop/src-tauri/icons/prod/32x32.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/32x32.png
rename to packages/desktop/src-tauri/icons/prod/32x32.png
diff --git a/packages/tauri/src-tauri/icons/prod/64x64.png b/packages/desktop/src-tauri/icons/prod/64x64.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/64x64.png
rename to packages/desktop/src-tauri/icons/prod/64x64.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square107x107Logo.png b/packages/desktop/src-tauri/icons/prod/Square107x107Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square107x107Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square107x107Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square142x142Logo.png b/packages/desktop/src-tauri/icons/prod/Square142x142Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square142x142Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square142x142Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square150x150Logo.png b/packages/desktop/src-tauri/icons/prod/Square150x150Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square150x150Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square150x150Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square284x284Logo.png b/packages/desktop/src-tauri/icons/prod/Square284x284Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square284x284Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square284x284Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square30x30Logo.png b/packages/desktop/src-tauri/icons/prod/Square30x30Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square30x30Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square30x30Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square310x310Logo.png b/packages/desktop/src-tauri/icons/prod/Square310x310Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square310x310Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square310x310Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square44x44Logo.png b/packages/desktop/src-tauri/icons/prod/Square44x44Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square44x44Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square44x44Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square71x71Logo.png b/packages/desktop/src-tauri/icons/prod/Square71x71Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square71x71Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square71x71Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/Square89x89Logo.png b/packages/desktop/src-tauri/icons/prod/Square89x89Logo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/Square89x89Logo.png
rename to packages/desktop/src-tauri/icons/prod/Square89x89Logo.png
diff --git a/packages/tauri/src-tauri/icons/prod/StoreLogo.png b/packages/desktop/src-tauri/icons/prod/StoreLogo.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/StoreLogo.png
rename to packages/desktop/src-tauri/icons/prod/StoreLogo.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml b/packages/desktop/src-tauri/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-hdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-mdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png
rename to packages/desktop/src-tauri/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png
diff --git a/packages/tauri/src-tauri/icons/prod/android/values/ic_launcher_background.xml b/packages/desktop/src-tauri/icons/prod/android/values/ic_launcher_background.xml
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/android/values/ic_launcher_background.xml
rename to packages/desktop/src-tauri/icons/prod/android/values/ic_launcher_background.xml
diff --git a/packages/tauri/src-tauri/icons/prod/icon.icns b/packages/desktop/src-tauri/icons/prod/icon.icns
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/icon.icns
rename to packages/desktop/src-tauri/icons/prod/icon.icns
diff --git a/packages/tauri/src-tauri/icons/prod/icon.ico b/packages/desktop/src-tauri/icons/prod/icon.ico
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/icon.ico
rename to packages/desktop/src-tauri/icons/prod/icon.ico
diff --git a/packages/tauri/src-tauri/icons/prod/icon.png b/packages/desktop/src-tauri/icons/prod/icon.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/icon.png
rename to packages/desktop/src-tauri/icons/prod/icon.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@1x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@1x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@1x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@2x-1.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@2x-1.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@2x-1.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@2x-1.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@3x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-20x20@3x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-20x20@3x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@1x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@1x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@1x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@2x-1.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@2x-1.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@2x-1.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@2x-1.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@3x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-29x29@3x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-29x29@3x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@1x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@1x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@1x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@2x-1.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@2x-1.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@2x-1.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@2x-1.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@3x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-40x40@3x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-40x40@3x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-512@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-512@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-512@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-512@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-60x60@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-60x60@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-60x60@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-60x60@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-60x60@3x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-60x60@3x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-60x60@3x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-60x60@3x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-76x76@1x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-76x76@1x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-76x76@1x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-76x76@1x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-76x76@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-76x76@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-76x76@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-76x76@2x.png
diff --git a/packages/tauri/src-tauri/icons/prod/ios/AppIcon-83.5x83.5@2x.png b/packages/desktop/src-tauri/icons/prod/ios/AppIcon-83.5x83.5@2x.png
similarity index 100%
rename from packages/tauri/src-tauri/icons/prod/ios/AppIcon-83.5x83.5@2x.png
rename to packages/desktop/src-tauri/icons/prod/ios/AppIcon-83.5x83.5@2x.png
diff --git a/packages/tauri/src-tauri/src/lib.rs b/packages/desktop/src-tauri/src/lib.rs
similarity index 100%
rename from packages/tauri/src-tauri/src/lib.rs
rename to packages/desktop/src-tauri/src/lib.rs
diff --git a/packages/tauri/src-tauri/src/main.rs b/packages/desktop/src-tauri/src/main.rs
similarity index 100%
rename from packages/tauri/src-tauri/src/main.rs
rename to packages/desktop/src-tauri/src/main.rs
diff --git a/packages/tauri/src-tauri/src/window_customizer.rs b/packages/desktop/src-tauri/src/window_customizer.rs
similarity index 100%
rename from packages/tauri/src-tauri/src/window_customizer.rs
rename to packages/desktop/src-tauri/src/window_customizer.rs
diff --git a/packages/tauri/src-tauri/tauri.conf.json b/packages/desktop/src-tauri/tauri.conf.json
similarity index 100%
rename from packages/tauri/src-tauri/tauri.conf.json
rename to packages/desktop/src-tauri/tauri.conf.json
diff --git a/packages/tauri/src-tauri/tauri.prod.conf.json b/packages/desktop/src-tauri/tauri.prod.conf.json
similarity index 100%
rename from packages/tauri/src-tauri/tauri.prod.conf.json
rename to packages/desktop/src-tauri/tauri.prod.conf.json
diff --git a/packages/tauri/src/index.tsx b/packages/desktop/src/index.tsx
similarity index 97%
rename from packages/tauri/src/index.tsx
rename to packages/desktop/src/index.tsx
index dc2c4047d..57c1fbe55 100644
--- a/packages/tauri/src/index.tsx
+++ b/packages/desktop/src/index.tsx
@@ -1,6 +1,6 @@
// @refresh reload
import { render } from "solid-js/web"
-import { App, PlatformProvider, Platform } from "@opencode-ai/desktop"
+import { App, PlatformProvider, Platform } from "@opencode-ai/app"
import { open, save } from "@tauri-apps/plugin-dialog"
import { open as shellOpen } from "@tauri-apps/plugin-shell"
import { type as ostype } from "@tauri-apps/plugin-os"
diff --git a/packages/tauri/src/menu.ts b/packages/desktop/src/menu.ts
similarity index 100%
rename from packages/tauri/src/menu.ts
rename to packages/desktop/src/menu.ts
diff --git a/packages/tauri/src/updater.ts b/packages/desktop/src/updater.ts
similarity index 100%
rename from packages/tauri/src/updater.ts
rename to packages/desktop/src/updater.ts
diff --git a/packages/desktop/tsconfig.json b/packages/desktop/tsconfig.json
index db04f79ca..64a6bc357 100644
--- a/packages/desktop/tsconfig.json
+++ b/packages/desktop/tsconfig.json
@@ -1,7 +1,5 @@
{
- "$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
- "composite": true,
"target": "ESNext",
"module": "ESNext",
"skipLibCheck": true,
@@ -12,13 +10,11 @@
"jsxImportSource": "solid-js",
"allowJs": true,
"strict": true,
- "noEmit": false,
- "emitDeclarationOnly": true,
- "outDir": "node_modules/.ts-dist",
"isolatedModules": true,
- "paths": {
- "@/*": ["./src/*"]
- }
+ "noEmit": true,
+ "emitDeclarationOnly": false,
+ "outDir": "node_modules/.ts-dist"
},
- "exclude": ["dist", "ts-dist"]
+ "references": [{ "path": "../app" }],
+ "include": ["src"]
}
diff --git a/packages/desktop/vite.config.ts b/packages/desktop/vite.config.ts
index 57071a894..123a2028c 100644
--- a/packages/desktop/vite.config.ts
+++ b/packages/desktop/vite.config.ts
@@ -1,15 +1,30 @@
import { defineConfig } from "vite"
-import desktopPlugin from "./vite"
+import appPlugin from "@opencode-ai/app/vite"
+const host = process.env.TAURI_DEV_HOST
+
+// https://vite.dev/config/
export default defineConfig({
- plugins: [desktopPlugin] as any,
+ plugins: [appPlugin],
+ // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
+ //
+ // 1. prevent Vite from obscuring rust errors
+ clearScreen: false,
+ // 2. tauri expects a fixed port, fail if that port is not available
server: {
- host: "0.0.0.0",
- allowedHosts: true,
- port: 3000,
- },
- build: {
- target: "esnext",
- sourcemap: true,
+ port: 1420,
+ strictPort: true,
+ host: host || false,
+ hmr: host
+ ? {
+ protocol: "ws",
+ host,
+ port: 1421,
+ }
+ : undefined,
+ watch: {
+ // 3. tell Vite to ignore watching `src-tauri`
+ ignored: ["**/src-tauri/**"],
+ },
},
})
diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json
index 602788abb..3df50aff2 100644
--- a/packages/enterprise/package.json
+++ b/packages/enterprise/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
- "version": "1.0.186",
+ "version": "1.0.191",
"private": true,
"type": "module",
"scripts": {
diff --git a/packages/enterprise/sst-env.d.ts b/packages/enterprise/sst-env.d.ts
index 632ea3fbe..ffa17f276 100644
--- a/packages/enterprise/sst-env.d.ts
+++ b/packages/enterprise/sst-env.d.ts
@@ -132,6 +132,7 @@ declare module "sst" {
"GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
"ZenData": cloudflare.R2Bucket
+ "ZenDataNew": cloudflare.R2Bucket
}
}
diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml
index 8d0141d7b..7e415b51f 100644
--- a/packages/extensions/zed/extension.toml
+++ b/packages/extensions/zed/extension.toml
@@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
-version = "1.0.186"
+version = "1.0.191"
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.186/opencode-darwin-arm64.zip"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.191/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.186/opencode-darwin-x64.zip"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.191/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
-archive = "https://github.com/sst/opencode/releases/download/v1.0.186/opencode-linux-arm64.tar.gz"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.191/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.186/opencode-linux-x64.tar.gz"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.191/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.186/opencode-windows-x64.zip"
+archive = "https://github.com/sst/opencode/releases/download/v1.0.191/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]
diff --git a/packages/function/package.json b/packages/function/package.json
index 593499d28..83de02f9d 100644
--- a/packages/function/package.json
+++ b/packages/function/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
- "version": "1.0.186",
+ "version": "1.0.191",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts
index 632ea3fbe..ffa17f276 100644
--- a/packages/function/sst-env.d.ts
+++ b/packages/function/sst-env.d.ts
@@ -132,6 +132,7 @@ declare module "sst" {
"GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
"ZenData": cloudflare.R2Bucket
+ "ZenDataNew": cloudflare.R2Bucket
}
}
diff --git a/packages/opencode/package.json b/packages/opencode/package.json
index dfba43513..59307256c 100644
--- a/packages/opencode/package.json
+++ b/packages/opencode/package.json
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
- "version": "1.0.186",
+ "version": "1.0.191",
"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",
diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts
index 90c8594cd..ad665e5d6 100644
--- a/packages/opencode/src/agent/agent.ts
+++ b/packages/opencode/src/agent/agent.ts
@@ -30,6 +30,7 @@ export namespace Agent {
permission: z.object({
edit: Config.Permission,
bash: z.record(z.string(), Config.Permission),
+ skill: z.record(z.string(), Config.Permission),
webfetch: Config.Permission.optional(),
doom_loop: Config.Permission.optional(),
external_directory: Config.Permission.optional(),
@@ -58,6 +59,9 @@ export namespace Agent {
bash: {
"*": "allow",
},
+ skill: {
+ "*": "allow",
+ },
webfetch: "allow",
doom_loop: "ask",
external_directory: "ask",
@@ -337,6 +341,17 @@ function mergeAgentPermissions(basePermission: any, overridePermission: any): Ag
"*": overridePermission.bash,
}
}
+
+ if (typeof basePermission.skill === "string") {
+ basePermission.skill = {
+ "*": basePermission.skill,
+ }
+ }
+ if (typeof overridePermission.skill === "string") {
+ overridePermission.skill = {
+ "*": overridePermission.skill,
+ }
+ }
const merged = mergeDeep(basePermission ?? {}, overridePermission ?? {}) as any
let mergedBash
if (merged.bash) {
@@ -354,10 +369,27 @@ function mergeAgentPermissions(basePermission: any, overridePermission: any): Ag
}
}
+ let mergedSkill
+ if (merged.skill) {
+ if (typeof merged.skill === "string") {
+ mergedSkill = {
+ "*": merged.skill,
+ }
+ } else if (typeof merged.skill === "object") {
+ mergedSkill = mergeDeep(
+ {
+ "*": "allow",
+ },
+ merged.skill,
+ )
+ }
+ }
+
const result: Agent.Info["permission"] = {
edit: merged.edit ?? "allow",
webfetch: merged.webfetch ?? "allow",
bash: mergedBash ?? { "*": "allow" },
+ skill: mergedSkill ?? { "*": "allow" },
doom_loop: merged.doom_loop,
external_directory: merged.external_directory,
}
diff --git a/packages/opencode/src/cli/cmd/debug/index.ts b/packages/opencode/src/cli/cmd/debug/index.ts
index 172987875..3b0aefa28 100644
--- a/packages/opencode/src/cli/cmd/debug/index.ts
+++ b/packages/opencode/src/cli/cmd/debug/index.ts
@@ -6,6 +6,7 @@ import { FileCommand } from "./file"
import { LSPCommand } from "./lsp"
import { RipgrepCommand } from "./ripgrep"
import { ScrapCommand } from "./scrap"
+import { SkillCommand } from "./skill"
import { SnapshotCommand } from "./snapshot"
export const DebugCommand = cmd({
@@ -17,6 +18,7 @@ export const DebugCommand = cmd({
.command(RipgrepCommand)
.command(FileCommand)
.command(ScrapCommand)
+ .command(SkillCommand)
.command(SnapshotCommand)
.command(PathsCommand)
.command({
diff --git a/packages/opencode/src/cli/cmd/debug/skill.ts b/packages/opencode/src/cli/cmd/debug/skill.ts
new file mode 100644
index 000000000..8079b688e
--- /dev/null
+++ b/packages/opencode/src/cli/cmd/debug/skill.ts
@@ -0,0 +1,15 @@
+import { EOL } from "os"
+import { Skill } from "../../../skill"
+import { bootstrap } from "../../bootstrap"
+import { cmd } from "../cmd"
+
+export const SkillCommand = cmd({
+ command: "skill",
+ builder: (yargs) => yargs,
+ async handler() {
+ await bootstrap(process.cwd(), async () => {
+ const skills = await Skill.all()
+ process.stdout.write(JSON.stringify(skills, null, 2) + EOL)
+ })
+ },
+})
diff --git a/packages/opencode/src/cli/cmd/mcp.ts b/packages/opencode/src/cli/cmd/mcp.ts
index 9ca4b3bff..b4ae8a37f 100644
--- a/packages/opencode/src/cli/cmd/mcp.ts
+++ b/packages/opencode/src/cli/cmd/mcp.ts
@@ -1,16 +1,41 @@
import { cmd } from "./cmd"
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
+import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
+import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js"
import * as prompts from "@clack/prompts"
import { UI } from "../ui"
import { MCP } from "../../mcp"
import { McpAuth } from "../../mcp/auth"
+import { McpOAuthProvider } from "../../mcp/oauth-provider"
import { Config } from "../../config/config"
import { Instance } from "../../project/instance"
+import { Installation } from "../../installation"
import path from "path"
-import os from "os"
import { Global } from "../../global"
+function getAuthStatusIcon(status: MCP.AuthStatus): string {
+ switch (status) {
+ case "authenticated":
+ return "✓"
+ case "expired":
+ return "⚠"
+ case "not_authenticated":
+ return "○"
+ }
+}
+
+function getAuthStatusText(status: MCP.AuthStatus): string {
+ switch (status) {
+ case "authenticated":
+ return "authenticated"
+ case "expired":
+ return "expired"
+ case "not_authenticated":
+ return "not authenticated"
+ }
+}
+
export const McpCommand = cmd({
command: "mcp",
builder: (yargs) =>
@@ -19,6 +44,7 @@ export const McpCommand = cmd({
.command(McpListCommand)
.command(McpAuthCommand)
.command(McpLogoutCommand)
+ .command(McpDebugCommand)
.demandCommand(),
async handler() {},
})
@@ -94,10 +120,12 @@ export const McpAuthCommand = cmd({
command: "auth [name]",
describe: "authenticate with an OAuth-enabled MCP server",
builder: (yargs) =>
- yargs.positional("name", {
- describe: "name of the MCP server",
- type: "string",
- }),
+ yargs
+ .positional("name", {
+ describe: "name of the MCP server",
+ type: "string",
+ })
+ .command(McpAuthListCommand),
async handler(args) {
await Instance.provide({
directory: process.cwd(),
@@ -108,20 +136,19 @@ export const McpAuthCommand = cmd({
const config = await Config.get()
const mcpServers = config.mcp ?? {}
- // Get OAuth-enabled servers
- const oauthServers = Object.entries(mcpServers).filter(([_, cfg]) => cfg.type === "remote" && !!cfg.oauth)
+ // Get OAuth-capable servers (remote servers with oauth not explicitly disabled)
+ const oauthServers = Object.entries(mcpServers).filter(
+ ([_, cfg]) => cfg.type === "remote" && cfg.oauth !== false,
+ )
if (oauthServers.length === 0) {
- prompts.log.warn("No OAuth-enabled MCP servers configured")
- prompts.log.info("Add OAuth config to a remote MCP server in opencode.json:")
+ prompts.log.warn("No OAuth-capable MCP servers configured")
+ prompts.log.info("Remote MCP servers support OAuth by default. Add a remote server in opencode.json:")
prompts.log.info(`
"mcp": {
"my-server": {
"type": "remote",
- "url": "https://example.com/mcp",
- "oauth": {
- "scope": "tools:read"
- }
+ "url": "https://example.com/mcp"
}
}`)
prompts.outro("Done")
@@ -130,13 +157,24 @@ export const McpAuthCommand = cmd({
let serverName = args.name
if (!serverName) {
+ // Build options with auth status
+ const options = await Promise.all(
+ oauthServers.map(async ([name, cfg]) => {
+ const authStatus = await MCP.getAuthStatus(name)
+ const icon = getAuthStatusIcon(authStatus)
+ const statusText = getAuthStatusText(authStatus)
+ const url = cfg.type === "remote" ? cfg.url : ""
+ return {
+ label: `${icon} ${name} (${statusText})`,
+ value: name,
+ hint: url,
+ }
+ }),
+ )
+
const selected = await prompts.select({
message: "Select MCP server to authenticate",
- options: oauthServers.map(([name, cfg]) => ({
- label: name,
- value: name,
- hint: cfg.type === "remote" ? cfg.url : undefined,
- })),
+ options,
})
if (prompts.isCancel(selected)) throw new UI.CancelledError()
serverName = selected
@@ -149,22 +187,24 @@ export const McpAuthCommand = cmd({
return
}
- if (serverConfig.type !== "remote" || !serverConfig.oauth) {
- prompts.log.error(`MCP server ${serverName} does not have OAuth configured`)
+ if (serverConfig.type !== "remote" || serverConfig.oauth === false) {
+ prompts.log.error(`MCP server ${serverName} does not support OAuth (oauth is disabled)`)
prompts.outro("Done")
return
}
// Check if already authenticated
- const hasTokens = await MCP.hasStoredTokens(serverName)
- if (hasTokens) {
+ const authStatus = await MCP.getAuthStatus(serverName)
+ if (authStatus === "authenticated") {
const confirm = await prompts.confirm({
- message: `${serverName} already has stored credentials. Re-authenticate?`,
+ message: `${serverName} already has valid credentials. Re-authenticate?`,
})
if (prompts.isCancel(confirm) || !confirm) {
prompts.outro("Cancelled")
return
}
+ } else if (authStatus === "expired") {
+ prompts.log.warn(`${serverName} has expired credentials. Re-authenticating...`)
}
const spinner = prompts.spinner()
@@ -207,6 +247,46 @@ export const McpAuthCommand = cmd({
},
})
+export const McpAuthListCommand = cmd({
+ command: "list",
+ aliases: ["ls"],
+ describe: "list OAuth-capable MCP servers and their auth status",
+ async handler() {
+ await Instance.provide({
+ directory: process.cwd(),
+ async fn() {
+ UI.empty()
+ prompts.intro("MCP OAuth Status")
+
+ const config = await Config.get()
+ const mcpServers = config.mcp ?? {}
+
+ // Get OAuth-capable servers
+ const oauthServers = Object.entries(mcpServers).filter(
+ ([_, cfg]) => cfg.type === "remote" && cfg.oauth !== false,
+ )
+
+ if (oauthServers.length === 0) {
+ prompts.log.warn("No OAuth-capable MCP servers configured")
+ prompts.outro("Done")
+ return
+ }
+
+ for (const [name, serverConfig] of oauthServers) {
+ const authStatus = await MCP.getAuthStatus(name)
+ const icon = getAuthStatusIcon(authStatus)
+ const statusText = getAuthStatusText(authStatus)
+ const url = serverConfig.type === "remote" ? serverConfig.url : ""
+
+ prompts.log.info(`${icon} ${name} ${UI.Style.TEXT_DIM}${statusText}\n ${UI.Style.TEXT_DIM}${url}`)
+ }
+
+ prompts.outro(`${oauthServers.length} OAuth-capable server(s)`)
+ },
+ })
+ },
+})
+
export const McpLogoutCommand = cmd({
command: "logout [name]",
describe: "remove OAuth credentials for an MCP server",
@@ -398,3 +478,177 @@ export const McpAddCommand = cmd({
prompts.outro("MCP server added successfully")
},
})
+
+export const McpDebugCommand = cmd({
+ command: "debug ",
+ describe: "debug OAuth connection for an MCP server",
+ builder: (yargs) =>
+ yargs.positional("name", {
+ describe: "name of the MCP server",
+ type: "string",
+ demandOption: true,
+ }),
+ async handler(args) {
+ await Instance.provide({
+ directory: process.cwd(),
+ async fn() {
+ UI.empty()
+ prompts.intro("MCP OAuth Debug")
+
+ const config = await Config.get()
+ const mcpServers = config.mcp ?? {}
+ const serverName = args.name
+
+ const serverConfig = mcpServers[serverName]
+ if (!serverConfig) {
+ prompts.log.error(`MCP server not found: ${serverName}`)
+ prompts.outro("Done")
+ return
+ }
+
+ if (serverConfig.type !== "remote") {
+ prompts.log.error(`MCP server ${serverName} is not a remote server`)
+ prompts.outro("Done")
+ return
+ }
+
+ if (serverConfig.oauth === false) {
+ prompts.log.warn(`MCP server ${serverName} has OAuth explicitly disabled`)
+ prompts.outro("Done")
+ return
+ }
+
+ prompts.log.info(`Server: ${serverName}`)
+ prompts.log.info(`URL: ${serverConfig.url}`)
+
+ // Check stored auth status
+ const authStatus = await MCP.getAuthStatus(serverName)
+ prompts.log.info(`Auth status: ${getAuthStatusIcon(authStatus)} ${getAuthStatusText(authStatus)}`)
+
+ const entry = await McpAuth.get(serverName)
+ if (entry?.tokens) {
+ prompts.log.info(` Access token: ${entry.tokens.accessToken.substring(0, 20)}...`)
+ if (entry.tokens.expiresAt) {
+ const expiresDate = new Date(entry.tokens.expiresAt * 1000)
+ const isExpired = entry.tokens.expiresAt < Date.now() / 1000
+ prompts.log.info(` Expires: ${expiresDate.toISOString()} ${isExpired ? "(EXPIRED)" : ""}`)
+ }
+ if (entry.tokens.refreshToken) {
+ prompts.log.info(` Refresh token: present`)
+ }
+ }
+ if (entry?.clientInfo) {
+ prompts.log.info(` Client ID: ${entry.clientInfo.clientId}`)
+ if (entry.clientInfo.clientSecretExpiresAt) {
+ const expiresDate = new Date(entry.clientInfo.clientSecretExpiresAt * 1000)
+ prompts.log.info(` Client secret expires: ${expiresDate.toISOString()}`)
+ }
+ }
+
+ const spinner = prompts.spinner()
+ spinner.start("Testing connection...")
+
+ // Test basic HTTP connectivity first
+ try {
+ const response = await fetch(serverConfig.url, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json, text/event-stream",
+ },
+ body: JSON.stringify({
+ jsonrpc: "2.0",
+ method: "initialize",
+ params: {
+ protocolVersion: "2024-11-05",
+ capabilities: {},
+ clientInfo: { name: "opencode-debug", version: Installation.VERSION },
+ },
+ id: 1,
+ }),
+ })
+
+ spinner.stop(`HTTP response: ${response.status} ${response.statusText}`)
+
+ // Check for WWW-Authenticate header
+ const wwwAuth = response.headers.get("www-authenticate")
+ if (wwwAuth) {
+ prompts.log.info(`WWW-Authenticate: ${wwwAuth}`)
+ }
+
+ if (response.status === 401) {
+ prompts.log.warn("Server returned 401 Unauthorized")
+
+ // Try to discover OAuth metadata
+ const oauthConfig = typeof serverConfig.oauth === "object" ? serverConfig.oauth : undefined
+ const authProvider = new McpOAuthProvider(
+ serverName,
+ serverConfig.url,
+ {
+ clientId: oauthConfig?.clientId,
+ clientSecret: oauthConfig?.clientSecret,
+ scope: oauthConfig?.scope,
+ },
+ {
+ onRedirect: async () => {},
+ },
+ )
+
+ prompts.log.info("Testing OAuth flow (without completing authorization)...")
+
+ // Try creating transport with auth provider to trigger discovery
+ const transport = new StreamableHTTPClientTransport(new URL(serverConfig.url), {
+ authProvider,
+ })
+
+ try {
+ const client = new Client({
+ name: "opencode-debug",
+ version: Installation.VERSION,
+ })
+ await client.connect(transport)
+ prompts.log.success("Connection successful (already authenticated)")
+ await client.close()
+ } catch (error) {
+ if (error instanceof UnauthorizedError) {
+ prompts.log.info(`OAuth flow triggered: ${error.message}`)
+
+ // Check if dynamic registration would be attempted
+ const clientInfo = await authProvider.clientInformation()
+ if (clientInfo) {
+ prompts.log.info(`Client ID available: ${clientInfo.client_id}`)
+ } else {
+ prompts.log.info("No client ID - dynamic registration will be attempted")
+ }
+ } else {
+ prompts.log.error(`Connection error: ${error instanceof Error ? error.message : String(error)}`)
+ }
+ }
+ } else if (response.status >= 200 && response.status < 300) {
+ prompts.log.success("Server responded successfully (no auth required or already authenticated)")
+ const body = await response.text()
+ try {
+ const json = JSON.parse(body)
+ if (json.result?.serverInfo) {
+ prompts.log.info(`Server info: ${JSON.stringify(json.result.serverInfo)}`)
+ }
+ } catch {
+ // Not JSON, ignore
+ }
+ } else {
+ prompts.log.warn(`Unexpected status: ${response.status}`)
+ const body = await response.text().catch(() => "")
+ if (body) {
+ prompts.log.info(`Response body: ${body.substring(0, 500)}`)
+ }
+ }
+ } catch (error) {
+ spinner.stop("Connection failed", 1)
+ prompts.log.error(`Error: ${error instanceof Error ? error.message : String(error)}`)
+ }
+
+ prompts.outro("Debug complete")
+ },
+ })
+ },
+})
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
index a892c83da..47940d0e2 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
@@ -14,7 +14,7 @@ import { Keybind } from "@/util/keybind"
import { usePromptHistory, type PromptInfo } from "./history"
import { type AutocompleteRef, Autocomplete } from "./autocomplete"
import { useCommandDialog } from "../dialog-command"
-import { useRenderer } from "@opentui/solid"
+import { useRenderer, useTerminalDimensions } from "@opentui/solid"
import { Editor } from "@tui/util/editor"
import { useExit } from "../../context/exit"
import { Clipboard } from "../../util/clipboard"
@@ -120,6 +120,9 @@ export function Prompt(props: PromptProps) {
const history = usePromptHistory()
const command = useCommandDialog()
const renderer = useRenderer()
+ const dimensions = useTerminalDimensions()
+ const tall = createMemo(() => dimensions().height > 40)
+ const wide = createMemo(() => dimensions().width > 120)
const { theme, syntax } = useTheme()
function promptModelWarning() {
@@ -310,6 +313,11 @@ export function Prompt(props: PromptProps) {
sdk.event.on(TuiEvent.PromptAppend.type, (evt) => {
input.insertText(evt.properties.text)
+ setTimeout(() => {
+ input.getLayoutNode().markDirty()
+ input.gotoBufferEnd()
+ renderer.requestRender()
+ }, 0)
})
createEffect(() => {
@@ -876,19 +884,21 @@ export function Prompt(props: PromptProps) {
cursorColor={theme.text}
syntaxStyle={syntax()}
/>
-
-
- {store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current().name)}{" "}
-
-
-
-
- {local.model.parsed().model}
-
- {local.model.parsed().provider}
-
-
-
+
+
+
+ {store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current().name)}{" "}
+
+
+
+
+ {local.model.parsed().model}
+
+ {local.model.parsed().provider}
+
+
+
+
- }>
-
-
- {/* @ts-ignore // SpinnerOptions doesn't support marginLeft */}
-
-
- {(() => {
- const retry = createMemo(() => {
- const s = status()
- if (s.type !== "retry") return
- return s
- })
- const message = createMemo(() => {
- const r = retry()
- if (!r) return
- if (r.message.includes("exceeded your current quota") && r.message.includes("gemini"))
- return "gemini is way too hot right now"
- if (r.message.length > 80) return r.message.slice(0, 80) + "..."
- return r.message
- })
- const isTruncated = createMemo(() => {
- const r = retry()
- if (!r) return false
- return r.message.length > 120
- })
- const [seconds, setSeconds] = createSignal(0)
- onMount(() => {
- const timer = setInterval(() => {
- const next = retry()?.next
- if (next) setSeconds(Math.round((next - Date.now()) / 1000))
- }, 1000)
-
- onCleanup(() => {
- clearInterval(timer)
+
+
+
+
+ {/* @ts-ignore // SpinnerOptions doesn't support marginLeft */}
+
+
+ {(() => {
+ const retry = createMemo(() => {
+ const s = status()
+ if (s.type !== "retry") return
+ return s
})
- })
- const handleMessageClick = () => {
- const r = retry()
- if (!r) return
- if (isTruncated()) {
- DialogAlert.show(dialog, "Retry Error", r.message)
+ const message = createMemo(() => {
+ const r = retry()
+ if (!r) return
+ if (r.message.includes("exceeded your current quota") && r.message.includes("gemini"))
+ return "gemini is way too hot right now"
+ if (r.message.length > 80) return r.message.slice(0, 80) + "..."
+ return r.message
+ })
+ const isTruncated = createMemo(() => {
+ const r = retry()
+ if (!r) return false
+ return r.message.length > 120
+ })
+ const [seconds, setSeconds] = createSignal(0)
+ onMount(() => {
+ const timer = setInterval(() => {
+ const next = retry()?.next
+ if (next) setSeconds(Math.round((next - Date.now()) / 1000))
+ }, 1000)
+
+ onCleanup(() => {
+ clearTimeout(timer)
+ })
+ })
+ const handleMessageClick = () => {
+ const r = retry()
+ if (!r) return
+ if (isTruncated()) {
+ DialogAlert.show(dialog, "Retry Error", r.message)
+ }
}
- }
- const retryText = () => {
- const r = retry()
- if (!r) return ""
- const baseMessage = message()
- const truncatedHint = isTruncated() ? " (click to expand)" : ""
- const retryInfo = ` [retrying ${seconds() > 0 ? `in ${seconds()}s ` : ""}attempt #${r.attempt}]`
- return baseMessage + truncatedHint + retryInfo
- }
+ const retryText = () => {
+ const r = retry()
+ if (!r) return ""
+ const baseMessage = message()
+ const truncatedHint = isTruncated() ? " (click to expand)" : ""
+ const retryInfo = ` [retrying ${seconds() > 0 ? `in ${seconds()}s ` : ""}attempt #${r.attempt}]`
+ return baseMessage + truncatedHint + retryInfo
+ }
- return (
-
-
- {retryText()}
-
-
- )
- })()}
+ return (
+
+
+ {retryText()}
+
+
+ )
+ })()}
+
+ 0 ? theme.primary : theme.text}>
+ esc{" "}
+ 0 ? theme.primary : theme.textMuted }}>
+ {store.interrupt > 0 ? "again to interrupt" : "interrupt"}
+
+
- 0 ? theme.primary : theme.text}>
- esc{" "}
- 0 ? theme.primary : theme.textMuted }}>
- {store.interrupt > 0 ? "again to interrupt" : "interrupt"}
-
-
-
-
-
-
-
-
+
+
+
+
+ {store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current().name)}{" "}
+
+
+
+
+ {local.model.parsed().model}
+
+ {local.model.parsed().provider}
+
+
+
+
+
+
+
+
+
{keybind.print("agent_cycle")} switch agent
+
+
- {keybind.print("command_list")} commands
+ {keybind.print("sidebar_toggle")} sidebar
-
-
-
- esc exit shell mode
-
-
-
-
-
+
+
+ {keybind.print("command_list")} commands
+
+
+
+
+ esc exit shell mode
+
+
+
+
>
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx
index bfdbfa51b..cf6abef47 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx
@@ -1,121 +1,140 @@
import { type Accessor, createMemo, Match, Show, Switch } from "solid-js"
import { useRouteData } from "@tui/context/route"
import { useSync } from "@tui/context/sync"
-import { pipe, sumBy } from "remeda"
import { useTheme } from "@tui/context/theme"
-import { SplitBorder, EmptyBorder } from "@tui/component/border"
-import type { AssistantMessage, Session } from "@opencode-ai/sdk/v2"
-import { useDirectory } from "../../context/directory"
+import { EmptyBorder } from "@tui/component/border"
+import type { Session } from "@opencode-ai/sdk/v2"
import { useKeybind } from "../../context/keybind"
+import { useTerminalDimensions } from "@opentui/solid"
-const Title = (props: { session: Accessor }) => {
+const Title = (props: { session: Accessor; truncate?: boolean }) => {
const { theme } = useTheme()
return (
-
+
# {props.session().title}
)
}
-const ContextInfo = (props: { context: Accessor; cost: Accessor }) => {
- const { theme } = useTheme()
- return (
-
-
- {props.context()} ({props.cost()})
-
-
- )
-}
-
export function Header() {
const route = useRouteData("session")
const sync = useSync()
const session = createMemo(() => sync.session.get(route.sessionID)!)
- const messages = createMemo(() => sync.data.message[route.sessionID] ?? [])
const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")
-
- const cost = createMemo(() => {
- const total = pipe(
- messages(),
- sumBy((x) => (x.role === "assistant" ? x.cost : 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.find((x) => x.id === last.providerID)?.models[last.modelID]
- let result = total.toLocaleString()
- if (model?.limit.context) {
- result += " " + Math.round((total / model.limit.context) * 100) + "%"
- }
- return result
- })
+ const showShare = createMemo(() => shareEnabled() && !session()?.share?.url)
const { theme } = useTheme()
const keybind = useKeybind()
+ const dimensions = useTerminalDimensions()
+ const tall = createMemo(() => dimensions().height > 40)
return (
-
-
-
-
- Subagent session
-
-
- Prev {keybind.print("session_child_cycle_reverse")}
-
-
- Next {keybind.print("session_child_cycle")}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {session().share!.url}
-
-
-
-
- /share copy link
-
-
-
-
+
+
+
+
+
+
+
+
+ Subagent session
+
+
+ Parent {keybind.print("session_parent")}
+
+
+ Prev {keybind.print("session_child_cycle_reverse")}
+
+
+ Next {keybind.print("session_child_cycle")}
+
+
+
+
+ /share{" "}
+
+
-
-
-
+
+
+
+
+
+
+ /share{" "}
+
+
+
+
+
+
+
+
+
)
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
index 3b1c58966..826fa2acf 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
@@ -22,6 +22,7 @@ import {
ScrollBoxRenderable,
addDefaultParsers,
MacOSScrollAccel,
+ RGBA,
type ScrollAcceleration,
} from "@opentui/core"
import { Prompt, type PromptRef } from "@tui/component/prompt"
@@ -129,13 +130,15 @@ export function Session() {
const [diffWrapMode, setDiffWrapMode] = createSignal<"word" | "none">("word")
const wide = createMemo(() => dimensions().width > 120)
+ const tall = createMemo(() => dimensions().height > 40)
const sidebarVisible = createMemo(() => {
if (session()?.parentID) return false
if (sidebar() === "show") return true
if (sidebar() === "auto" && wide()) return true
return false
})
- const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4)
+ const sidebarOverlay = createMemo(() => sidebarVisible() && !wide())
+ const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() && !sidebarOverlay() ? 42 : 0) - 4)
const scrollAcceleration = createMemo(() => {
const tui = sync.data.config.tui
@@ -870,6 +873,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)
@@ -944,7 +964,7 @@ export function Session() {
-
+
-
+
-
+
+
+ setSidebar("hide")}
+ >
+ e.stopPropagation()}>
+
+
+
+
)
@@ -1629,33 +1667,15 @@ ToolRegistry.register({
ToolRegistry.register({
name: "task",
- container: "inline",
+ container: "block",
render(props) {
const { theme } = useTheme()
const keybind = useKeybind()
const dialog = useDialog()
const renderer = useRenderer()
- const [hover, setHover] = createSignal(false)
return (
- setHover(true)}
- onMouseOut={() => setHover(false)}
- onMouseUp={() => {
- const id = props.metadata.sessionId
- if (renderer.getSelection()?.getSelectedText() || !id) return
- dialog.replace(() => )
- }}
- >
+ <>
{Locale.titlecase(props.input.subagent_type ?? "unknown")} Task "{props.input.description}"
@@ -1678,7 +1698,7 @@ ToolRegistry.register({
{keybind.print("session_child_cycle")}, {keybind.print("session_child_cycle_reverse")}
to navigate between subagent sessions
-
+ >
)
},
})
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
index 6c74e04fa..0bc4e860f 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
@@ -29,6 +29,16 @@ export function Sidebar(props: { sessionID: string }) {
// Sort MCP servers alphabetically for consistent display order
const mcpEntries = createMemo(() => Object.entries(sync.data.mcp).sort(([a], [b]) => a.localeCompare(b)))
+ // Count connected and error MCP servers for collapsed header display
+ const connectedMcpCount = createMemo(() => mcpEntries().filter(([_, item]) => item.status === "connected").length)
+ const errorMcpCount = createMemo(
+ () =>
+ mcpEntries().filter(
+ ([_, item]) =>
+ item.status === "failed" || item.status === "needs_auth" || item.status === "needs_client_registration",
+ ).length,
+ )
+
const cost = createMemo(() => {
const total = messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0)
return new Intl.NumberFormat("en-US", {
@@ -62,6 +72,7 @@ export function Sidebar(props: { sessionID: string }) {
MCP
+
+
+ {" "}
+ ({connectedMcpCount()} active
+ {errorMcpCount() > 0 ? `, ${errorMcpCount()} error${errorMcpCount() > 1 ? "s" : ""}` : ""})
+
+
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index daf81f434..cb93c0ebf 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -414,6 +414,7 @@ export namespace Config {
.object({
edit: Permission.optional(),
bash: z.union([Permission, z.record(z.string(), Permission)]).optional(),
+ skill: z.union([Permission, z.record(z.string(), Permission)]).optional(),
webfetch: Permission.optional(),
doom_loop: Permission.optional(),
external_directory: Permission.optional(),
@@ -562,6 +563,7 @@ export namespace Config {
history_next: z.string().optional().default("down").describe("Next history item"),
session_child_cycle: z.string().optional().default("right").describe("Next child session"),
session_child_cycle_reverse: z.string().optional().default("left").describe("Previous child session"),
+ session_parent: z.string().optional().default("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"),
})
@@ -763,6 +765,7 @@ export namespace Config {
.object({
edit: Permission.optional(),
bash: z.union([Permission, z.record(z.string(), Permission)]).optional(),
+ skill: z.union([Permission, z.record(z.string(), Permission)]).optional(),
webfetch: Permission.optional(),
doom_loop: Permission.optional(),
external_directory: Permission.optional(),
diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts
index 00d9e8c38..22b714b85 100644
--- a/packages/opencode/src/file/ripgrep.ts
+++ b/packages/opencode/src/file/ripgrep.ts
@@ -240,7 +240,8 @@ export namespace Ripgrep {
if (done) break
buffer += decoder.decode(value, { stream: true })
- const lines = buffer.split("\n")
+ // Handle both Unix (\n) and Windows (\r\n) line endings
+ const lines = buffer.split(/\r?\n/)
buffer = lines.pop() || ""
for (const line of lines) {
@@ -379,7 +380,8 @@ export namespace Ripgrep {
return []
}
- const lines = result.text().trim().split("\n").filter(Boolean)
+ // Handle both Unix (\n) and Windows (\r\n) line endings
+ const lines = result.text().trim().split(/\r?\n/).filter(Boolean)
// Parse JSON lines from ripgrep output
return lines
diff --git a/packages/opencode/src/lsp/language.ts b/packages/opencode/src/lsp/language.ts
index 12792c7c2..620944a8e 100644
--- a/packages/opencode/src/lsp/language.ts
+++ b/packages/opencode/src/lsp/language.ts
@@ -111,4 +111,6 @@ export const LANGUAGE_EXTENSIONS: Record = {
".tfvars": "terraform-vars",
".hcl": "hcl",
".nix": "nix",
+ ".typ": "typst",
+ ".typc": "typst",
} as const
diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts
index e0c8de998..b432e5a5d 100644
--- a/packages/opencode/src/lsp/server.ts
+++ b/packages/opencode/src/lsp/server.ts
@@ -1798,4 +1798,98 @@ export namespace LSPServer {
}
},
}
+
+ 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 }),
+ }
+ },
+ }
}
diff --git a/packages/opencode/src/mcp/auth.ts b/packages/opencode/src/mcp/auth.ts
index 6ebb95698..7f7dbd156 100644
--- a/packages/opencode/src/mcp/auth.ts
+++ b/packages/opencode/src/mcp/auth.ts
@@ -121,4 +121,15 @@ export namespace McpAuth {
await set(mcpName, entry)
}
}
+
+ /**
+ * Check if stored tokens are expired.
+ * Returns null if no tokens exist, false if no expiry or not expired, true if expired.
+ */
+ export async function isTokenExpired(mcpName: string): Promise {
+ const entry = await get(mcpName)
+ if (!entry?.tokens) return null
+ if (!entry.tokens.expiresAt) return false
+ return entry.tokens.expiresAt < Date.now() / 1000
+ }
}
diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts
index 2f8e4ace4..40ee25565 100644
--- a/packages/opencode/src/mcp/index.ts
+++ b/packages/opencode/src/mcp/index.ts
@@ -15,6 +15,8 @@ import { withTimeout } from "@/util/timeout"
import { McpOAuthProvider } from "./oauth-provider"
import { McpOAuthCallback } from "./oauth-callback"
import { McpAuth } from "./auth"
+import { Bus } from "@/bus"
+import { TuiEvent } from "@/cli/cmd/tui/event"
import open from "open"
export namespace MCP {
@@ -251,10 +253,24 @@ export namespace MCP {
status: "needs_client_registration" as const,
error: "Server does not support dynamic client registration. Please provide clientId in config.",
}
+ // Show toast for needs_client_registration
+ Bus.publish(TuiEvent.ToastShow, {
+ title: "MCP Authentication Required",
+ message: `Server "${key}" requires a pre-registered client ID. Add clientId to your config.`,
+ variant: "warning",
+ duration: 8000,
+ }).catch((e) => log.debug("failed to show toast", { error: e }))
} else {
// Store transport for later finishAuth call
pendingOAuthTransports.set(key, transport)
status = { status: "needs_auth" as const }
+ // Show toast for needs_auth
+ Bus.publish(TuiEvent.ToastShow, {
+ title: "MCP Authentication Required",
+ message: `Server "${key}" requires authentication. Run: opencode mcp auth ${key}`,
+ variant: "warning",
+ duration: 8000,
+ }).catch((e) => log.debug("failed to show toast", { error: e }))
}
break
}
@@ -623,4 +639,16 @@ export namespace MCP {
const entry = await McpAuth.get(mcpName)
return !!entry?.tokens
}
+
+ export type AuthStatus = "authenticated" | "expired" | "not_authenticated"
+
+ /**
+ * Get the authentication status for an MCP server.
+ */
+ export async function getAuthStatus(mcpName: string): Promise {
+ const hasTokens = await hasStoredTokens(mcpName)
+ if (!hasTokens) return "not_authenticated"
+ const expired = await McpAuth.isTokenExpired(mcpName)
+ return expired ? "expired" : "authenticated"
+ }
}
diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts
index b8d4dadbd..b11ca9368 100644
--- a/packages/opencode/src/provider/provider.ts
+++ b/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
})()
diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts
index 76403a4ed..d86fe9022 100644
--- a/packages/opencode/src/provider/transform.ts
+++ b/packages/opencode/src/provider/transform.ts
@@ -216,6 +216,7 @@ export namespace ProviderTransform {
if (id.includes("claude")) return undefined
if (id.includes("gemini-3-pro")) return 1.0
if (id.includes("glm-4.6")) return 1.0
+ if (id.includes("glm-4.7")) return 1.0
if (id.includes("minimax-m2")) return 1.0
if (id.includes("kimi-k2")) {
if (id.includes("thinking")) return 1.0
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index e92c46225..c74dbbb41 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -47,6 +47,7 @@ import { SessionStatus } from "@/session/status"
import { upgradeWebSocket, websocket } from "hono/bun"
import { errors } from "./error"
import { Pty } from "@/pty"
+import { Installation } from "@/installation"
// @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85
globalThis.AI_SDK_LOG_WARNINGS = false
@@ -96,6 +97,27 @@ export namespace Server {
}
})
.use(cors())
+ .get(
+ "/global/health",
+ describeRoute({
+ summary: "Get health",
+ description: "Get health information about the OpenCode server.",
+ operationId: "global.health",
+ responses: {
+ 200: {
+ description: "Health information",
+ content: {
+ "application/json": {
+ schema: resolver(z.object({ healthy: z.literal(true), version: z.string() })),
+ },
+ },
+ },
+ },
+ }),
+ async (c) => {
+ return c.json({ healthy: true, version: Installation.VERSION })
+ },
+ )
.get(
"/global/event",
describeRoute({
@@ -2578,10 +2600,10 @@ export namespace Server {
},
)
.all("/*", async (c) => {
- return proxy(`https://desktop.opencode.ai${c.req.path}`, {
+ return proxy(`https://app.opencode.ai${c.req.path}`, {
...c.req,
headers: {
- host: "desktop.opencode.ai",
+ host: "app.opencode.ai",
},
})
}),
diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts
index 3e4c8020d..339ba2f42 100644
--- a/packages/opencode/src/session/compaction.ts
+++ b/packages/opencode/src/session/compaction.ts
@@ -40,6 +40,8 @@ export namespace SessionCompaction {
export const PRUNE_MINIMUM = 20_000
export const PRUNE_PROTECT = 40_000
+ const PRUNE_PROTECTED_TOOLS = ["skill"]
+
// goes backwards through parts until there are 40_000 tokens worth of tool
// calls. then erases output of previous tool calls. idea is to throw away old
// tool calls that are no longer relevant.
@@ -61,6 +63,8 @@ export namespace SessionCompaction {
const part = msg.parts[partIndex]
if (part.type === "tool")
if (part.state.status === "completed") {
+ if (PRUNE_PROTECTED_TOOLS.includes(part.tool)) continue
+
if (part.state.time.compacted) break loop
const estimate = Token.estimate(part.state.output)
total += estimate
@@ -126,12 +130,15 @@ export namespace SessionCompaction {
model,
abort: input.abort,
})
- // Allow plugins to inject context for compaction
+ // Allow plugins to inject context or replace compaction prompt
const compacting = await Plugin.trigger(
"experimental.session.compacting",
{ sessionID: input.sessionID },
- { context: [] },
+ { context: [], prompt: undefined },
)
+ const defaultPrompt =
+ "Provide a detailed prompt for continuing our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next considering new session will not have access to our conversation."
+ const promptText = compacting.prompt ?? [defaultPrompt, ...compacting.context].join("\n\n")
const result = await processor.process({
user: userMessage,
agent,
@@ -146,10 +153,7 @@ export namespace SessionCompaction {
content: [
{
type: "text",
- text: [
- "Provide a detailed prompt for continuing our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next considering new session will not have access to our conversation.",
- ...compacting.context,
- ].join("\n\n"),
+ text: promptText,
},
],
},
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index e393e2fab..fabe3fa51 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -532,11 +532,7 @@ export namespace SessionPrompt {
agent,
abort,
sessionID,
- system: [
- ...(await SystemPrompt.environment()),
- ...(await SystemPrompt.skills()),
- ...(await SystemPrompt.custom()),
- ],
+ system: [...(await SystemPrompt.environment()), ...(await SystemPrompt.custom())],
messages: [
...MessageV2.toModelMessage(sessionMessages),
...(isLastStep
@@ -587,7 +583,7 @@ export namespace SessionPrompt {
mergeDeep(await ToolRegistry.enabled(input.agent)),
mergeDeep(input.tools ?? {}),
)
- for (const item of await ToolRegistry.tools(input.model.providerID)) {
+ for (const item of await ToolRegistry.tools(input.model.providerID, input.agent)) {
if (Wildcard.all(item.id, enabledTools) === false) continue
const schema = ProviderTransform.schema(input.model, z.toJSONSchema(item.parameters))
tools[item.id] = tool({
diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts
index a9d0586b4..300943881 100644
--- a/packages/opencode/src/session/system.ts
+++ b/packages/opencode/src/session/system.ts
@@ -14,7 +14,6 @@ import PROMPT_POLARIS from "./prompt/polaris.txt"
import PROMPT_BEAST from "./prompt/beast.txt"
import PROMPT_GEMINI from "./prompt/gemini.txt"
import PROMPT_ANTHROPIC_SPOOF from "./prompt/anthropic_spoof.txt"
-import PROMPT_COMPACTION from "./prompt/compaction.txt"
import PROMPT_CODEX from "./prompt/codex.txt"
import type { Provider } from "@/provider/provider"
@@ -118,25 +117,4 @@ export namespace SystemPrompt {
)
return Promise.all(found).then((result) => result.filter(Boolean))
}
-
- export async function skills() {
- const all = await Skill.all()
- if (all.length === 0) return []
-
- const lines = [
- "You have access to skills listed in ``. When a task matches a skill's description, read its SKILL.md file to get detailed instructions.",
- "",
- "",
- ]
- for (const skill of all) {
- lines.push(" ")
- lines.push(` ${skill.name}`)
- lines.push(` ${skill.description}`)
- lines.push(` ${skill.location}`)
- lines.push(" ")
- }
- lines.push("")
-
- return [lines.join("\n")]
- }
}
diff --git a/packages/opencode/src/skill/skill.ts b/packages/opencode/src/skill/skill.ts
index 88182c5de..41df88f8b 100644
--- a/packages/opencode/src/skill/skill.ts
+++ b/packages/opencode/src/skill/skill.ts
@@ -1,7 +1,5 @@
-import path from "path"
import z from "zod"
import { Config } from "../config/config"
-import { Filesystem } from "../util/filesystem"
import { Instance } from "../project/instance"
import { NamedError } from "@opencode-ai/util/error"
import { ConfigMarkdown } from "../config/markdown"
@@ -9,35 +7,12 @@ import { Log } from "../util/log"
export namespace Skill {
const log = Log.create({ service: "skill" })
-
- // Name: 1-64 chars, lowercase alphanumeric and hyphens, no consecutive hyphens, can't start/end with hyphen
- const NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/
-
- export const Frontmatter = z.object({
- name: z
- .string()
- .min(1)
- .max(64)
- .refine((val) => NAME_REGEX.test(val), {
- message:
- "Name must be lowercase alphanumeric with hyphens, no consecutive hyphens, cannot start or end with hyphen",
- }),
- description: z.string().min(1).max(1024),
- license: z.string().optional(),
- compatibility: z.string().max(500).optional(),
- metadata: z.record(z.string(), z.string()).optional(),
+ export const Info = z.object({
+ name: z.string(),
+ description: z.string(),
+ location: z.string(),
})
-
- export type Frontmatter = z.infer
-
- export interface Info {
- name: string
- description: string
- location: string
- license?: string
- compatibility?: string
- metadata?: Record
- }
+ export type Info = z.infer
export const InvalidError = NamedError.create(
"SkillInvalidError",
@@ -57,15 +32,12 @@ export namespace Skill {
}),
)
- const SKILL_GLOB = new Bun.Glob("skill/*/SKILL.md")
- const CLAUDE_SKILL_GLOB = new Bun.Glob("*/SKILL.md")
+ const SKILL_GLOB = new Bun.Glob("skill/**/SKILL.md")
- async function discover(): Promise {
+ export const state = Instance.state(async () => {
const directories = await Config.directories()
+ const skills: Record = {}
- const paths: string[] = []
-
- // Scan skill/ subdirectory in config directories (.opencode/, ~/.opencode/, etc.)
for (const dir of directories) {
for await (const match of SKILL_GLOB.scan({
cwd: dir,
@@ -73,82 +45,39 @@ export namespace Skill {
onlyFiles: true,
followSymlinks: true,
})) {
- paths.push(match)
+ const md = await ConfigMarkdown.parse(match)
+ if (!md) {
+ continue
+ }
+
+ const parsed = Info.pick({ name: true, description: true }).safeParse(md.data)
+ if (!parsed.success) continue
+
+ // Warn on duplicate skill names
+ if (skills[parsed.data.name]) {
+ log.warn("duplicate skill name", {
+ name: parsed.data.name,
+ existing: skills[parsed.data.name].location,
+ duplicate: match,
+ })
+ }
+
+ skills[parsed.data.name] = {
+ name: parsed.data.name,
+ description: parsed.data.description,
+ location: match,
+ }
}
}
- // 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,
- })) {
- paths.push(match)
- }
- }
-
- return paths
- }
-
- async function load(skillMdPath: string): Promise {
- const md = await ConfigMarkdown.parse(skillMdPath)
- if (!md.data) {
- throw new InvalidError({
- path: skillMdPath,
- message: "SKILL.md must have YAML frontmatter",
- })
- }
-
- const parsed = Frontmatter.safeParse(md.data)
- if (!parsed.success) {
- throw new InvalidError({
- path: skillMdPath,
- issues: parsed.error.issues,
- })
- }
-
- const frontmatter = parsed.data
- const skillDir = path.dirname(skillMdPath)
- const dirName = path.basename(skillDir)
-
- if (frontmatter.name !== dirName) {
- throw new NameMismatchError({
- path: skillMdPath,
- expected: dirName,
- actual: frontmatter.name,
- })
- }
-
- return {
- name: frontmatter.name,
- description: frontmatter.description,
- location: skillMdPath,
- license: frontmatter.license,
- compatibility: frontmatter.compatibility,
- metadata: frontmatter.metadata,
- }
- }
-
- export const state = Instance.state(async () => {
- const paths = await discover()
- const skills: Info[] = []
-
- for (const skillPath of paths) {
- const info = await load(skillPath)
- log.info("loaded skill", { name: info.name, location: info.location })
- skills.push(info)
- }
-
return skills
})
- export async function all(): Promise {
- return state()
+ export async function get(name: string) {
+ return state().then((x) => x[name])
+ }
+
+ export async function all() {
+ return state().then((x) => Object.values(x))
}
}
diff --git a/packages/opencode/src/tool/grep.ts b/packages/opencode/src/tool/grep.ts
index 99af448ba..d73bc1616 100644
--- a/packages/opencode/src/tool/grep.ts
+++ b/packages/opencode/src/tool/grep.ts
@@ -49,7 +49,8 @@ export const GrepTool = Tool.define("grep", {
throw new Error(`ripgrep failed: ${errorOutput}`)
}
- const lines = output.trim().split("\n")
+ // Handle both Unix (\n) and Windows (\r\n) line endings
+ const lines = output.trim().split(/\r?\n/)
const matches = []
for (const line of lines) {
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index 3a695f45f..69a45432d 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -10,6 +10,7 @@ import { TodoWriteTool, TodoReadTool } from "./todo"
import { WebFetchTool } from "./webfetch"
import { WriteTool } from "./write"
import { InvalidTool } from "./invalid"
+import { SkillTool } from "./skill"
import type { Agent } from "../agent/agent"
import { Tool } from "./tool"
import { Instance } from "../project/instance"
@@ -103,6 +104,7 @@ export namespace ToolRegistry {
TodoReadTool,
WebSearchTool,
CodeSearchTool,
+ SkillTool,
...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [LspTool] : []),
...(config.experimental?.batch_tool === true ? [BatchTool] : []),
...custom,
@@ -113,7 +115,7 @@ export namespace ToolRegistry {
return all().then((x) => x.map((t) => t.id))
}
- export async function tools(providerID: string) {
+ export async function tools(providerID: string, agent?: Agent.Info) {
const tools = await all()
const result = await Promise.all(
tools
@@ -128,7 +130,7 @@ export namespace ToolRegistry {
using _ = log.time(t.id)
return {
id: t.id,
- ...(await t.init()),
+ ...(await t.init({ agent })),
}
}),
)
@@ -150,6 +152,10 @@ export namespace ToolRegistry {
result["codesearch"] = false
result["websearch"] = false
}
+ // Disable skill tool if all skills are denied
+ if (agent.permission.skill["*"] === "deny" && Object.keys(agent.permission.skill).length === 1) {
+ result["skill"] = false
+ }
return result
}
diff --git a/packages/opencode/src/tool/skill.ts b/packages/opencode/src/tool/skill.ts
new file mode 100644
index 000000000..2503f7639
--- /dev/null
+++ b/packages/opencode/src/tool/skill.ts
@@ -0,0 +1,100 @@
+import path from "path"
+import z from "zod"
+import { Tool } from "./tool"
+import { Skill } from "../skill"
+import { Agent } from "../agent/agent"
+import { Permission } from "../permission"
+import { Wildcard } from "../util/wildcard"
+import { ConfigMarkdown } from "../config/markdown"
+
+const parameters = z.object({
+ name: z.string().describe("The skill identifier from available_skills (e.g., 'code-review')"),
+})
+
+export const SkillTool: Tool.Info = {
+ id: "skill",
+ async init(ctx) {
+ const skills = await Skill.all()
+
+ // Filter skills by agent permissions if agent provided
+ let accessibleSkills = skills
+ if (ctx?.agent) {
+ const permissions = ctx.agent.permission.skill
+ accessibleSkills = skills.filter((skill) => {
+ const action = Wildcard.all(skill.name, permissions)
+ return action !== "deny"
+ })
+ }
+
+ return {
+ description: [
+ "Load a skill to get detailed instructions for a specific task.",
+ "Skills provide specialized knowledge and step-by-step guidance.",
+ "Use this when a task matches an available skill's description.",
+ "",
+ ...accessibleSkills.flatMap((skill) => [
+ ` `,
+ ` ${skill.name}`,
+ ` ${skill.description}`,
+ ` `,
+ ]),
+ "",
+ ].join(" "),
+ parameters,
+ async execute(params, ctx) {
+ const agent = await Agent.get(ctx.agent)
+
+ const skill = await Skill.get(params.name)
+
+ if (!skill) {
+ const available = await Skill.all().then((x) => x.map((s) => s.name).join(", "))
+ throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`)
+ }
+
+ // Check permission using Wildcard.all on the skill name
+ const permissions = agent.permission.skill
+ const action = Wildcard.all(params.name, permissions)
+
+ if (action === "deny") {
+ throw new Permission.RejectedError(
+ ctx.sessionID,
+ "skill",
+ ctx.callID,
+ { skill: params.name },
+ `Access to skill "${params.name}" is denied for agent "${agent.name}".`,
+ )
+ }
+
+ if (action === "ask") {
+ await Permission.ask({
+ type: "skill",
+ pattern: params.name,
+ sessionID: ctx.sessionID,
+ messageID: ctx.messageID,
+ callID: ctx.callID,
+ title: `Load skill: ${skill.name}`,
+ metadata: { name: skill.name, description: skill.description },
+ })
+ }
+
+ // Load and parse skill content
+ const parsed = await ConfigMarkdown.parse(skill.location)
+ const dir = path.dirname(skill.location)
+
+ // Format output similar to plugin pattern
+ const output = [`## Skill: ${skill.name}`, "", `**Base directory**: ${dir}`, "", parsed.content.trim()].join(
+ "\n",
+ )
+
+ return {
+ title: `Loaded skill: ${skill.name}`,
+ output,
+ metadata: {
+ name: skill.name,
+ dir,
+ },
+ }
+ },
+ }
+ },
+}
diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts
index 80b6abe8c..acee24902 100644
--- a/packages/opencode/src/tool/tool.ts
+++ b/packages/opencode/src/tool/tool.ts
@@ -1,11 +1,16 @@
import z from "zod"
import type { MessageV2 } from "../session/message-v2"
+import type { Agent } from "../agent/agent"
export namespace Tool {
interface Metadata {
[key: string]: any
}
+ export interface InitContext {
+ agent?: Agent.Info
+ }
+
export type Context = {
sessionID: string
messageID: string
@@ -17,7 +22,7 @@ export namespace Tool {
}
export interface Info {
id: string
- init: () => Promise<{
+ init: (ctx?: InitContext) => Promise<{
description: string
parameters: Parameters
execute(
@@ -42,8 +47,8 @@ export namespace Tool {
): Info {
return {
id,
- init: async () => {
- const toolInfo = init instanceof Function ? await init() : init
+ init: async (ctx) => {
+ const toolInfo = init instanceof Function ? await init(ctx) : init
const execute = toolInfo.execute
toolInfo.execute = (args, ctx) => {
try {
diff --git a/packages/opencode/test/skill/skill.test.ts b/packages/opencode/test/skill/skill.test.ts
index 3d7bc4c23..4a1d75f9f 100644
--- a/packages/opencode/test/skill/skill.test.ts
+++ b/packages/opencode/test/skill/skill.test.ts
@@ -65,55 +65,7 @@ description: Another test skill.
})
})
-test("throws error for invalid skill name format", async () => {
- await using tmp = await tmpdir({
- git: true,
- init: async (dir) => {
- const skillDir = path.join(dir, ".opencode", "skill", "InvalidName")
- await Bun.write(
- path.join(skillDir, "SKILL.md"),
- `---
-name: InvalidName
-description: A skill with invalid name.
----
-`,
- )
- },
- })
-
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- await expect(Skill.all()).rejects.toThrow()
- },
- })
-})
-
-test("throws error when name doesn't match directory", async () => {
- await using tmp = await tmpdir({
- git: true,
- init: async (dir) => {
- const skillDir = path.join(dir, ".opencode", "skill", "dir-name")
- await Bun.write(
- path.join(skillDir, "SKILL.md"),
- `---
-name: different-name
-description: A skill with mismatched name.
----
-`,
- )
- },
- })
-
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- await expect(Skill.all()).rejects.toThrow("SkillNameMismatchError")
- },
- })
-})
-
-test("throws error for missing frontmatter", async () => {
+test("skips skills with missing frontmatter", async () => {
await using tmp = await tmpdir({
git: true,
init: async (dir) => {
@@ -128,78 +80,11 @@ Just some content without YAML frontmatter.
},
})
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- await expect(Skill.all()).rejects.toThrow("SkillInvalidError")
- },
- })
-})
-
-test("parses optional fields", async () => {
- await using tmp = await tmpdir({
- git: true,
- init: async (dir) => {
- const skillDir = path.join(dir, ".opencode", "skill", "full-skill")
- await Bun.write(
- path.join(skillDir, "SKILL.md"),
- `---
-name: full-skill
-description: A skill with all optional fields.
-license: MIT
-compatibility: Requires Node.js 18+
-metadata:
- author: test-author
- version: "1.0"
----
-
-# Full Skill
-`,
- )
- },
- })
-
await Instance.provide({
directory: tmp.path,
fn: async () => {
const skills = await Skill.all()
- expect(skills.length).toBe(1)
- expect(skills[0].license).toBe("MIT")
- expect(skills[0].compatibility).toBe("Requires Node.js 18+")
- expect(skills[0].metadata).toEqual({
- author: "test-author",
- version: "1.0",
- })
- },
- })
-})
-
-test("ignores unknown frontmatter fields", async () => {
- await using tmp = await tmpdir({
- git: true,
- init: async (dir) => {
- const skillDir = path.join(dir, ".opencode", "skill", "extra-fields")
- await Bun.write(
- path.join(skillDir, "SKILL.md"),
- `---
-name: extra-fields
-description: A skill with extra unknown fields.
-allowed-tools: Bash Read Write
-some-other-field: ignored
----
-
-# Extra Fields Skill
-`,
- )
- },
- })
-
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- const skills = await Skill.all()
- expect(skills.length).toBe(1)
- expect(skills[0].name).toBe("extra-fields")
+ expect(skills).toEqual([])
},
})
})
@@ -216,76 +101,31 @@ test("returns empty array when no skills exist", async () => {
})
})
-test("SystemPrompt.skills() returns empty array when no skills", async () => {
- await using tmp = await tmpdir({ git: true })
+// 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.
+// ---
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- const result = await SystemPrompt.skills()
- expect(result).toEqual([])
- },
- })
-})
+// # Claude Skill
+// `,
+// )
+// },
+// })
-test("SystemPrompt.skills() returns XML block with skills", async () => {
- await using tmp = await tmpdir({
- git: true,
- init: async (dir) => {
- const skillDir = path.join(dir, ".opencode", "skill", "example-skill")
- await Bun.write(
- path.join(skillDir, "SKILL.md"),
- `---
-name: example-skill
-description: An example skill for testing XML output.
----
-
-# Example
-`,
- )
- },
- })
-
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- const result = await SystemPrompt.skills()
- expect(result.length).toBe(1)
- expect(result[0]).toContain("")
- expect(result[0]).toContain("example-skill")
- expect(result[0]).toContain("An example skill for testing XML output.")
- expect(result[0]).toContain("SKILL.md")
- expect(result[0]).toContain("")
- expect(result[0]).toContain("When a task matches a skill's description")
- },
- })
-})
-
-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
-`,
- )
- },
- })
-
- 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")
+// },
+// })
+// })
diff --git a/packages/opencode/test/tool/grep.test.ts b/packages/opencode/test/tool/grep.test.ts
new file mode 100644
index 000000000..f3da666a0
--- /dev/null
+++ b/packages/opencode/test/tool/grep.test.ts
@@ -0,0 +1,108 @@
+import { describe, expect, test } from "bun:test"
+import path from "path"
+import { GrepTool } from "../../src/tool/grep"
+import { Instance } from "../../src/project/instance"
+import { tmpdir } from "../fixture/fixture"
+
+const ctx = {
+ sessionID: "test",
+ messageID: "",
+ callID: "",
+ agent: "build",
+ abort: AbortSignal.any([]),
+ metadata: () => {},
+}
+
+const projectRoot = path.join(__dirname, "../..")
+
+describe("tool.grep", () => {
+ test("basic search", async () => {
+ await Instance.provide({
+ directory: projectRoot,
+ fn: async () => {
+ const grep = await GrepTool.init()
+ const result = await grep.execute(
+ {
+ pattern: "export",
+ path: path.join(projectRoot, "src/tool"),
+ include: "*.ts",
+ },
+ ctx,
+ )
+ expect(result.metadata.matches).toBeGreaterThan(0)
+ expect(result.output).toContain("Found")
+ },
+ })
+ })
+
+ test("no matches returns correct output", async () => {
+ await using tmp = await tmpdir({
+ init: async (dir) => {
+ await Bun.write(path.join(dir, "test.txt"), "hello world")
+ },
+ })
+ await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const grep = await GrepTool.init()
+ const result = await grep.execute(
+ {
+ pattern: "xyznonexistentpatternxyz123",
+ path: tmp.path,
+ },
+ ctx,
+ )
+ expect(result.metadata.matches).toBe(0)
+ expect(result.output).toBe("No files found")
+ },
+ })
+ })
+
+ test("handles CRLF line endings in output", async () => {
+ // This test verifies the regex split handles both \n and \r\n
+ await using tmp = await tmpdir({
+ init: async (dir) => {
+ // Create a test file with content
+ await Bun.write(path.join(dir, "test.txt"), "line1\nline2\nline3")
+ },
+ })
+ await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const grep = await GrepTool.init()
+ const result = await grep.execute(
+ {
+ pattern: "line",
+ path: tmp.path,
+ },
+ ctx,
+ )
+ expect(result.metadata.matches).toBeGreaterThan(0)
+ },
+ })
+ })
+})
+
+describe("CRLF regex handling", () => {
+ test("regex correctly splits Unix line endings", () => {
+ const unixOutput = "file1.txt|1|content1\nfile2.txt|2|content2\nfile3.txt|3|content3"
+ const lines = unixOutput.trim().split(/\r?\n/)
+ expect(lines.length).toBe(3)
+ expect(lines[0]).toBe("file1.txt|1|content1")
+ expect(lines[2]).toBe("file3.txt|3|content3")
+ })
+
+ test("regex correctly splits Windows CRLF line endings", () => {
+ const windowsOutput = "file1.txt|1|content1\r\nfile2.txt|2|content2\r\nfile3.txt|3|content3"
+ const lines = windowsOutput.trim().split(/\r?\n/)
+ expect(lines.length).toBe(3)
+ expect(lines[0]).toBe("file1.txt|1|content1")
+ expect(lines[2]).toBe("file3.txt|3|content3")
+ })
+
+ test("regex handles mixed line endings", () => {
+ const mixedOutput = "file1.txt|1|content1\nfile2.txt|2|content2\r\nfile3.txt|3|content3"
+ const lines = mixedOutput.trim().split(/\r?\n/)
+ expect(lines.length).toBe(3)
+ })
+})
diff --git a/packages/plugin/package.json b/packages/plugin/package.json
index 9da158f1d..babe21271 100644
--- a/packages/plugin/package.json
+++ b/packages/plugin/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
- "version": "1.0.186",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
@@ -24,4 +24,4 @@
"typescript": "catalog:",
"@typescript/native-preview": "catalog:"
}
-}
+}
\ No newline at end of file
diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts
index 487e6ed3e..fbc0e710c 100644
--- a/packages/plugin/src/index.ts
+++ b/packages/plugin/src/index.ts
@@ -192,10 +192,16 @@ export interface Hooks {
},
) => Promise
/**
- * Called before session compaction starts. Allows plugins to append
- * additional context to the compaction prompt.
+ * Called before session compaction starts. Allows plugins to customize
+ * the compaction prompt.
+ *
+ * - `context`: Additional context strings appended to the default prompt
+ * - `prompt`: If set, replaces the default compaction prompt entirely
*/
- "experimental.session.compacting"?: (input: { sessionID: string }, output: { context: string[] }) => Promise
+ "experimental.session.compacting"?: (
+ input: { sessionID: string },
+ output: { context: string[]; prompt?: string },
+ ) => Promise
"experimental.text.complete"?: (
input: { sessionID: string; messageID: string; partID: string },
output: { text: string },
diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json
index 81498a60f..6278ebaef 100644
--- a/packages/sdk/js/package.json
+++ b/packages/sdk/js/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
- "version": "1.0.186",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
@@ -29,4 +29,4 @@
"publishConfig": {
"directory": "dist"
}
-}
+}
\ No newline at end of file
diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts
index fa7a86463..97bc92b86 100644
--- a/packages/sdk/js/src/v2/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts
@@ -30,6 +30,7 @@ import type {
FormatterStatusResponses,
GlobalDisposeResponses,
GlobalEventResponses,
+ GlobalHealthResponses,
InstanceDisposeResponses,
LspStatusResponses,
McpAddErrors,
@@ -188,6 +189,18 @@ class HeyApiRegistry {
}
export class Global extends HeyApiClient {
+ /**
+ * Get health
+ *
+ * Get health information about the OpenCode server.
+ */
+ public health(options?: Options) {
+ return (options?.client ?? this.client).get({
+ url: "/global/health",
+ ...options,
+ })
+ }
+
/**
* Get global events
*
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index e3249848c..1372765e3 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -547,6 +547,48 @@ export type EventSessionCompacted = {
}
}
+export type EventTuiPromptAppend = {
+ type: "tui.prompt.append"
+ properties: {
+ text: string
+ }
+}
+
+export type EventTuiCommandExecute = {
+ type: "tui.command.execute"
+ properties: {
+ command:
+ | "session.list"
+ | "session.new"
+ | "session.share"
+ | "session.interrupt"
+ | "session.compact"
+ | "session.page.up"
+ | "session.page.down"
+ | "session.half.page.up"
+ | "session.half.page.down"
+ | "session.first"
+ | "session.last"
+ | "prompt.clear"
+ | "prompt.submit"
+ | "agent.cycle"
+ | string
+ }
+}
+
+export type EventTuiToastShow = {
+ type: "tui.toast.show"
+ properties: {
+ title?: string
+ message: string
+ variant: "info" | "success" | "warning" | "error"
+ /**
+ * Duration in milliseconds
+ */
+ duration?: number
+ }
+}
+
export type EventCommandExecuted = {
type: "command.executed"
properties: {
@@ -639,48 +681,6 @@ export type EventVcsBranchUpdated = {
}
}
-export type EventTuiPromptAppend = {
- type: "tui.prompt.append"
- properties: {
- text: string
- }
-}
-
-export type EventTuiCommandExecute = {
- type: "tui.command.execute"
- properties: {
- command:
- | "session.list"
- | "session.new"
- | "session.share"
- | "session.interrupt"
- | "session.compact"
- | "session.page.up"
- | "session.page.down"
- | "session.half.page.up"
- | "session.half.page.down"
- | "session.first"
- | "session.last"
- | "prompt.clear"
- | "prompt.submit"
- | "agent.cycle"
- | string
- }
-}
-
-export type EventTuiToastShow = {
- type: "tui.toast.show"
- properties: {
- title?: string
- message: string
- variant: "info" | "success" | "warning" | "error"
- /**
- * Duration in milliseconds
- */
- duration?: number
- }
-}
-
export type Pty = {
id: string
title: string
@@ -752,6 +752,9 @@ export type Event =
| EventSessionStatus
| EventSessionIdle
| EventSessionCompacted
+ | EventTuiPromptAppend
+ | EventTuiCommandExecute
+ | EventTuiToastShow
| EventCommandExecuted
| EventSessionCreated
| EventSessionUpdated
@@ -760,9 +763,6 @@ export type Event =
| EventSessionError
| EventFileWatcherUpdated
| EventVcsBranchUpdated
- | EventTuiPromptAppend
- | EventTuiCommandExecute
- | EventTuiToastShow
| EventPtyCreated
| EventPtyUpdated
| EventPtyExited
@@ -1122,6 +1122,10 @@ export type KeybindsConfig = {
* Previous child session
*/
session_child_cycle_reverse?: string
+ /**
+ * Go to parent session
+ */
+ session_parent?: string
/**
* Suspend terminal
*/
@@ -1163,6 +1167,13 @@ export type AgentConfig = {
| {
[key: string]: "ask" | "allow" | "deny"
}
+ skill?:
+ | "ask"
+ | "allow"
+ | "deny"
+ | {
+ [key: string]: "ask" | "allow" | "deny"
+ }
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
@@ -1189,6 +1200,13 @@ export type AgentConfig = {
| {
[key: string]: "ask" | "allow" | "deny"
}
+ skill?:
+ | "ask"
+ | "allow"
+ | "deny"
+ | {
+ [key: string]: "ask" | "allow" | "deny"
+ }
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
@@ -1508,6 +1526,13 @@ export type Config = {
| {
[key: string]: "ask" | "allow" | "deny"
}
+ skill?:
+ | "ask"
+ | "allow"
+ | "deny"
+ | {
+ [key: string]: "ask" | "allow" | "deny"
+ }
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
@@ -1788,6 +1813,9 @@ export type Agent = {
bash: {
[key: string]: "ask" | "allow" | "deny"
}
+ skill: {
+ [key: string]: "ask" | "allow" | "deny"
+ }
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
@@ -1869,6 +1897,25 @@ export type WellKnownAuth = {
export type Auth = OAuth | ApiAuth | WellKnownAuth
+export type GlobalHealthData = {
+ body?: never
+ path?: never
+ query?: never
+ url: "/global/health"
+}
+
+export type GlobalHealthResponses = {
+ /**
+ * Health information
+ */
+ 200: {
+ healthy: true
+ version: string
+ }
+}
+
+export type GlobalHealthResponse = GlobalHealthResponses[keyof GlobalHealthResponses]
+
export type GlobalEventData = {
body?: never
path?: never
diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json
index a1576668a..588b130b9 100644
--- a/packages/sdk/openapi.json
+++ b/packages/sdk/openapi.json
@@ -6,6 +6,41 @@
"version": "1.0.0"
},
"paths": {
+ "/global/health": {
+ "get": {
+ "operationId": "global.health",
+ "summary": "Get health",
+ "description": "Get health information about the OpenCode server.",
+ "responses": {
+ "200": {
+ "description": "Health information",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "healthy": {
+ "type": "boolean",
+ "const": true
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "required": ["healthy", "version"]
+ }
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.global.health({\n ...\n})"
+ }
+ ]
+ }
+ },
"/global/event": {
"get": {
"operationId": "global.event",
@@ -6499,6 +6534,98 @@
},
"required": ["type", "properties"]
},
+ "Event.tui.prompt.append": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "tui.prompt.append"
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string"
+ }
+ },
+ "required": ["text"]
+ }
+ },
+ "required": ["type", "properties"]
+ },
+ "Event.tui.command.execute": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "tui.command.execute"
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "command": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": [
+ "session.list",
+ "session.new",
+ "session.share",
+ "session.interrupt",
+ "session.compact",
+ "session.page.up",
+ "session.page.down",
+ "session.half.page.up",
+ "session.half.page.down",
+ "session.first",
+ "session.last",
+ "prompt.clear",
+ "prompt.submit",
+ "agent.cycle"
+ ]
+ },
+ {
+ "type": "string"
+ }
+ ]
+ }
+ },
+ "required": ["command"]
+ }
+ },
+ "required": ["type", "properties"]
+ },
+ "Event.tui.toast.show": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "tui.toast.show"
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ },
+ "variant": {
+ "type": "string",
+ "enum": ["info", "success", "warning", "error"]
+ },
+ "duration": {
+ "description": "Duration in milliseconds",
+ "default": 5000,
+ "type": "number"
+ }
+ },
+ "required": ["message", "variant"]
+ }
+ },
+ "required": ["type", "properties"]
+ },
"Event.command.executed": {
"type": "object",
"properties": {
@@ -6793,98 +6920,6 @@
},
"required": ["type", "properties"]
},
- "Event.tui.prompt.append": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "const": "tui.prompt.append"
- },
- "properties": {
- "type": "object",
- "properties": {
- "text": {
- "type": "string"
- }
- },
- "required": ["text"]
- }
- },
- "required": ["type", "properties"]
- },
- "Event.tui.command.execute": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "const": "tui.command.execute"
- },
- "properties": {
- "type": "object",
- "properties": {
- "command": {
- "anyOf": [
- {
- "type": "string",
- "enum": [
- "session.list",
- "session.new",
- "session.share",
- "session.interrupt",
- "session.compact",
- "session.page.up",
- "session.page.down",
- "session.half.page.up",
- "session.half.page.down",
- "session.first",
- "session.last",
- "prompt.clear",
- "prompt.submit",
- "agent.cycle"
- ]
- },
- {
- "type": "string"
- }
- ]
- }
- },
- "required": ["command"]
- }
- },
- "required": ["type", "properties"]
- },
- "Event.tui.toast.show": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "const": "tui.toast.show"
- },
- "properties": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "message": {
- "type": "string"
- },
- "variant": {
- "type": "string",
- "enum": ["info", "success", "warning", "error"]
- },
- "duration": {
- "description": "Duration in milliseconds",
- "default": 5000,
- "type": "number"
- }
- },
- "required": ["message", "variant"]
- }
- },
- "required": ["type", "properties"]
- },
"Pty": {
"type": "object",
"properties": {
@@ -7079,6 +7114,15 @@
{
"$ref": "#/components/schemas/Event.session.compacted"
},
+ {
+ "$ref": "#/components/schemas/Event.tui.prompt.append"
+ },
+ {
+ "$ref": "#/components/schemas/Event.tui.command.execute"
+ },
+ {
+ "$ref": "#/components/schemas/Event.tui.toast.show"
+ },
{
"$ref": "#/components/schemas/Event.command.executed"
},
@@ -7103,15 +7147,6 @@
{
"$ref": "#/components/schemas/Event.vcs.branch.updated"
},
- {
- "$ref": "#/components/schemas/Event.tui.prompt.append"
- },
- {
- "$ref": "#/components/schemas/Event.tui.command.execute"
- },
- {
- "$ref": "#/components/schemas/Event.tui.toast.show"
- },
{
"$ref": "#/components/schemas/Event.pty.created"
},
@@ -7598,6 +7633,11 @@
"default": "left",
"type": "string"
},
+ "session_parent": {
+ "description": "Go to parent session",
+ "default": "up",
+ "type": "string"
+ },
"terminal_suspend": {
"description": "Suspend terminal",
"default": "ctrl+z",
@@ -7682,6 +7722,24 @@
}
]
},
+ "skill": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": ["ask", "allow", "deny"]
+ },
+ {
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string",
+ "enum": ["ask", "allow", "deny"]
+ }
+ }
+ ]
+ },
"webfetch": {
"type": "string",
"enum": ["ask", "allow", "deny"]
@@ -8390,6 +8448,24 @@
}
]
},
+ "skill": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": ["ask", "allow", "deny"]
+ },
+ {
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string",
+ "enum": ["ask", "allow", "deny"]
+ }
+ }
+ ]
+ },
"webfetch": {
"type": "string",
"enum": ["ask", "allow", "deny"]
@@ -9199,6 +9275,16 @@
"enum": ["ask", "allow", "deny"]
}
},
+ "skill": {
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string",
+ "enum": ["ask", "allow", "deny"]
+ }
+ },
"webfetch": {
"type": "string",
"enum": ["ask", "allow", "deny"]
@@ -9212,7 +9298,7 @@
"enum": ["ask", "allow", "deny"]
}
},
- "required": ["edit", "bash"]
+ "required": ["edit", "bash", "skill"]
},
"model": {
"type": "object",
diff --git a/packages/slack/package.json b/packages/slack/package.json
index 1d85ced4e..4be3b2ef1 100644
--- a/packages/slack/package.json
+++ b/packages/slack/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
- "version": "1.0.186",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"dev": "bun run src/index.ts",
diff --git a/packages/tauri/.gitignore b/packages/tauri/.gitignore
deleted file mode 100644
index a547bf36d..000000000
--- a/packages/tauri/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/packages/tauri/README.md b/packages/tauri/README.md
deleted file mode 100644
index b381dcf5b..000000000
--- a/packages/tauri/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Tauri + Vanilla TS
-
-This template should help get you started developing with Tauri in vanilla HTML, CSS and Typescript.
-
-## Recommended IDE Setup
-
-- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
diff --git a/packages/tauri/package.json b/packages/tauri/package.json
deleted file mode 100644
index ff068c65a..000000000
--- a/packages/tauri/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "@opencode-ai/tauri",
- "private": true,
- "version": "1.0.186",
- "type": "module",
- "scripts": {
- "typecheck": "tsgo -b",
- "predev": "bun ./scripts/predev.ts",
- "dev": "vite",
- "build": "bun run typecheck && vite build",
- "preview": "vite preview",
- "tauri": "tauri"
- },
- "dependencies": {
- "@opencode-ai/desktop": "workspace:*",
- "@solid-primitives/storage": "catalog:",
- "@tauri-apps/api": "^2",
- "@tauri-apps/plugin-dialog": "~2",
- "@tauri-apps/plugin-opener": "^2",
- "@tauri-apps/plugin-os": "~2",
- "@tauri-apps/plugin-process": "~2",
- "@tauri-apps/plugin-shell": "~2",
- "@tauri-apps/plugin-store": "~2",
- "@tauri-apps/plugin-updater": "~2",
- "@tauri-apps/plugin-http": "~2",
- "@tauri-apps/plugin-window-state": "~2",
- "solid-js": "catalog:"
- },
- "devDependencies": {
- "@actions/artifact": "4.0.0",
- "@tauri-apps/cli": "^2",
- "@types/bun": "catalog:",
- "@typescript/native-preview": "catalog:",
- "typescript": "~5.6.2",
- "vite": "catalog:"
- }
-}
diff --git a/packages/tauri/vite.config.ts b/packages/tauri/vite.config.ts
deleted file mode 100644
index ead3d8a8d..000000000
--- a/packages/tauri/vite.config.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { defineConfig } from "vite"
-import desktopPlugin from "@opencode-ai/desktop/vite"
-
-const host = process.env.TAURI_DEV_HOST
-
-// https://vite.dev/config/
-export default defineConfig({
- plugins: [desktopPlugin],
- // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
- //
- // 1. prevent Vite from obscuring rust errors
- clearScreen: false,
- // 2. tauri expects a fixed port, fail if that port is not available
- server: {
- port: 1420,
- strictPort: true,
- host: host || false,
- hmr: host
- ? {
- protocol: "ws",
- host,
- port: 1421,
- }
- : undefined,
- watch: {
- // 3. tell Vite to ignore watching `src-tauri`
- ignored: ["**/src-tauri/**"],
- },
- },
-})
diff --git a/packages/ui/package.json b/packages/ui/package.json
index f1fd5b9d8..47a002967 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
- "version": "1.0.186",
+ "version": "1.0.191",
"type": "module",
"exports": {
"./*": "./src/components/*.tsx",
diff --git a/packages/util/package.json b/packages/util/package.json
index f2fb03145..9194b1e9f 100644
--- a/packages/util/package.json
+++ b/packages/util/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/util",
- "version": "1.0.186",
+ "version": "1.0.191",
"private": true,
"type": "module",
"exports": {
diff --git a/packages/web/package.json b/packages/web/package.json
index 9b2609dec..6f9ba171c 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/web",
"type": "module",
- "version": "1.0.186",
+ "version": "1.0.191",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
@@ -28,7 +28,6 @@
"marked-shiki": "1.2.1",
"rehype-autolink-headings": "7.1.0",
"remeda": "catalog:",
- "sharp": "0.32.5",
"shiki": "3.4.2",
"solid-js": "catalog:",
"toolbeam-docs-theme": "0.4.8"
diff --git a/packages/web/src/content/docs/ecosystem.mdx b/packages/web/src/content/docs/ecosystem.mdx
index 8f7b201b6..48ae971fe 100644
--- a/packages/web/src/content/docs/ecosystem.mdx
+++ b/packages/web/src/content/docs/ecosystem.mdx
@@ -29,6 +29,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Enables AI agents to run background processes in a PTY, send interactive input to them. |
| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Track OpenCode usage with Wakatime |
| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Clean up markdown tables produced by LLMs |
+| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x faster code editing with Morph Fast Apply API and lazy edit markers |
| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Background agents, pre-built LSP/AST/MCP tools, curated agents, Claude Code compatible |
| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-powered automatic Zellij session naming based on OpenCode context |
@@ -44,6 +45,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template for building OpenCode plugins |
| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Neovim frontend for opencode - a terminal-based AI coding agent |
| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Vercel AI SDK provider for using OpenCode via @opencode-ai/sdk |
+| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Web / Desktop App and VS Code Extension for OpenCode |
---
diff --git a/packages/web/src/content/docs/gitlab.mdx b/packages/web/src/content/docs/gitlab.mdx
index 66c006c80..e8f43f85f 100644
--- a/packages/web/src/content/docs/gitlab.mdx
+++ b/packages/web/src/content/docs/gitlab.mdx
@@ -3,12 +3,55 @@ title: GitLab
description: Use OpenCode in GitLab issues and merge requests.
---
+OpenCode integrates with your GitLab workflow through your GitLab CI/CD pipeline or with GitLab Duo.
+
+In both cases, OpenCode will run on your GitLab runners.
+
+---
+
+## GitLab CI
+
+OpenCode works in a regular GitLab pipeline. You can build it into a pipeline as a [CI component](https://docs.gitlab.com/ee/ci/components/)
+
+Here we are using a community-created CI/CD component for OpenCode — [nagyv/gitlab-opencode](https://gitlab.com/nagyv/gitlab-opencode).
+
+---
+
+### Features
+
+- **Use custom configuration per job**: Configure OpenCode with a custom configuration directory, for example `./config/#custom-directory` to enable or disable functionality per OpenCode invocation.
+- **Minimal setup**: The CI component sets up OpenCode in the background, you only need to create the OpenCode configuration and the initial prompt.
+- **Flexible**: The CI component supports several inputs for customizing its behavior
+
+---
+
+### Setup
+
+1. Store your OpenCode authentication JSON as a File type CI environment variables under **Settings** > **CI/CD** > **Variables**. Make sure to mark them as "Masked and hidden".
+2. Add the following to your `.gitlab-ci.yml` file.
+
+ ```yaml title=".gitlab-ci.yml"
+ include:
+ - component: $CI_SERVER_FQDN/nagyv/gitlab-opencode/opencode@1.0.0
+ inputs:
+ config_dir: ${CI_PROJECT_DIR}/opencode-config
+ auth_json: $OPENCODE_AUTH_JSON # The variable name for your OpenCode authentication JSON
+ command: optional-custom-command
+ message: "Your prompt here"
+ ```
+
+For more inputs and use cases [check out the docs](https://gitlab.com/explore/catalog/nagyv/gitlab-opencode) for this component.
+
+---
+
+## GitLab Duo
+
OpenCode integrates with your GitLab workflow.
Mention `@opencode` in a comment, and OpenCode will execute tasks within your GitLab CI pipeline.
---
-## Features
+### Features
- **Triage issues**: Ask OpenCode to look into an issue and explain it to you.
- **Fix and implement**: Ask OpenCode to fix an issue or implement a feature.
@@ -17,7 +60,7 @@ Mention `@opencode` in a comment, and OpenCode will execute tasks within your Gi
---
-## Setup
+### Setup
OpenCode runs in your GitLab CI/CD pipeline, here's what you'll need to set it up:
@@ -113,7 +156,7 @@ You can refer to the [GitLab CLI agents docs](https://docs.gitlab.com/user/duo_a
---
-## Examples
+### Examples
Here are some examples of how you can use OpenCode in GitLab.
diff --git a/packages/web/src/content/docs/lsp.mdx b/packages/web/src/content/docs/lsp.mdx
index b546c1991..230f782d3 100644
--- a/packages/web/src/content/docs/lsp.mdx
+++ b/packages/web/src/content/docs/lsp.mdx
@@ -37,6 +37,7 @@ OpenCode comes with several built-in LSP servers for popular languages:
| sourcekit-lsp | .swift, .objc, .objcpp | `swift` installed (`xcode` on macOS) |
| svelte | .svelte | Auto-installs for Svelte projects |
| terraform | .tf, .tfvars | Auto-installs from GitHub releases |
+| tinymist | .typ, .typc | Auto-installs from GitHub releases |
| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project |
| vue | .vue | Auto-installs for Vue projects |
| yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server |
diff --git a/packages/web/src/content/docs/plugins.mdx b/packages/web/src/content/docs/plugins.mdx
index 6982b4c93..6be545482 100644
--- a/packages/web/src/content/docs/plugins.mdx
+++ b/packages/web/src/content/docs/plugins.mdx
@@ -233,3 +233,30 @@ Include any state that should persist across compaction:
```
The `experimental.session.compacting` hook fires before the LLM generates a continuation summary. Use it to inject domain-specific context that the default compaction prompt would miss.
+
+You can also replace the compaction prompt entirely by setting `output.prompt`:
+
+```ts title=".opencode/plugin/custom-compaction.ts"
+import type { Plugin } from "@opencode-ai/plugin"
+
+export const CustomCompactionPlugin: Plugin = async (ctx) => {
+ return {
+ "experimental.session.compacting": async (input, output) => {
+ // Replace the entire compaction prompt
+ output.prompt = `
+You are generating a continuation prompt for a multi-agent swarm session.
+
+Summarize:
+1. The current task and its status
+2. Which files are being modified and by whom
+3. Any blockers or dependencies between agents
+4. The next steps to complete the work
+
+Format as a structured prompt that a new agent can use to resume work.
+`
+ },
+ }
+}
+```
+
+When `output.prompt` is set, it completely replaces the default compaction prompt. The `output.context` array is ignored in this case.
diff --git a/packages/web/src/content/docs/sdk.mdx b/packages/web/src/content/docs/sdk.mdx
index 4f9a2959f..1ff843103 100644
--- a/packages/web/src/content/docs/sdk.mdx
+++ b/packages/web/src/content/docs/sdk.mdx
@@ -123,6 +123,23 @@ The SDK exposes all server APIs through a type-safe client.
---
+### Global
+
+| Method | Description | Response |
+| ----------------- | ------------------------------- | ------------------------------------ |
+| `global.health()` | Check server health and version | `{ healthy: true, version: string }` |
+
+---
+
+#### Examples
+
+```javascript
+const health = await client.global.health()
+console.log(health.data.version)
+```
+
+---
+
### App
| Method | Description | Response |
diff --git a/packages/web/src/content/docs/server.mdx b/packages/web/src/content/docs/server.mdx
index 60aff2003..427d8f505 100644
--- a/packages/web/src/content/docs/server.mdx
+++ b/packages/web/src/content/docs/server.mdx
@@ -68,11 +68,12 @@ The opencode server exposes the following APIs.
---
-### Global Events
+### Global
-| Method | Path | Description | Response |
-| ------ | --------------- | ------------------------------ | ------------ |
-| `GET` | `/global/event` | Get global events (SSE stream) | Event stream |
+| Method | Path | Description | Response |
+| ------ | ---------------- | ------------------------------ | ------------------------------------ |
+| `GET` | `/global/health` | Get server health and version | `{ healthy: true, version: string }` |
+| `GET` | `/global/event` | Get global events (SSE stream) | Event stream |
---
diff --git a/packages/web/src/content/docs/skills.mdx b/packages/web/src/content/docs/skills.mdx
index 217d4b3d2..c1d433a83 100644
--- a/packages/web/src/content/docs/skills.mdx
+++ b/packages/web/src/content/docs/skills.mdx
@@ -4,7 +4,7 @@ description: "Define reusable behavior via SKILL.md definitions"
---
Agent skills let OpenCode discover reusable instructions from your repo or home directory.
-When a conversation matches a skill, the agent is prompted to read its `SKILL.md`.
+Skills are loaded on-demand via the native `skill` tool—agents see available skills and can load the full content when needed.
---
@@ -97,24 +97,123 @@ Ask clarifying questions if the target versioning scheme is unclear.
---
-## Recognize prompt injection
+## Recognize tool description
-OpenCode adds an `` XML block to the system prompt.
-Each entry includes the skill name, description, and its discovered location.
+OpenCode lists available skills in the `skill` tool description.
+Each entry includes the skill name and description:
```xml
git-release
Create consistent releases and changelogs
- .opencode/skill/git-release/SKILL.md
```
+The agent loads a skill by calling the tool:
+
+```
+skill({ name: "git-release" })
+```
+
+---
+
+## Configure permissions
+
+Control which skills agents can access using pattern-based permissions in `opencode.json`:
+
+```json
+{
+ "permission": {
+ "skill": {
+ "pr-review": "allow",
+ "internal-*": "deny",
+ "experimental-*": "ask",
+ "*": "allow"
+ }
+ }
+}
+```
+
+| Permission | Behavior |
+| ---------- | ----------------------------------------- |
+| `allow` | Skill loads immediately |
+| `deny` | Skill hidden from agent, access rejected |
+| `ask` | User prompted for approval before loading |
+
+Patterns support wildcards: `internal-*` matches `internal-docs`, `internal-tools`, etc.
+
+---
+
+## Override per agent
+
+Give specific agents different permissions than the global defaults.
+
+**For custom agents** (in agent frontmatter):
+
+```yaml
+---
+permission:
+ skill:
+ "documents-*": "allow"
+---
+```
+
+**For built-in agents** (in `opencode.json`):
+
+```json
+{
+ "agent": {
+ "plan": {
+ "permission": {
+ "skill": {
+ "internal-*": "allow"
+ }
+ }
+ }
+ }
+}
+```
+
+---
+
+## Disable the skill tool
+
+Completely disable skills for agents that shouldn't use them:
+
+**For custom agents**:
+
+```yaml
+---
+tools:
+ skill: false
+---
+```
+
+**For built-in agents**:
+
+```json
+{
+ "agent": {
+ "plan": {
+ "tools": {
+ "skill": false
+ }
+ }
+ }
+}
+```
+
+When disabled, the `` section is omitted entirely.
+
---
## Troubleshoot loading
-If a skill does not show up, verify the folder name matches `name` exactly.
-Also check that `SKILL.md` is spelled in all caps and includes frontmatter.
+If a skill does not show up:
+
+1. Verify `SKILL.md` is spelled in all caps
+2. Check that frontmatter includes `name` and `description`
+3. Ensure skill names are unique across all locations
+4. Check permissions—skills with `deny` are hidden from agents
diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx
index 134271ca1..4b268ab4f 100644
--- a/packages/web/src/content/docs/zen.mdx
+++ b/packages/web/src/content/docs/zen.mdx
@@ -77,6 +77,7 @@ You can also access our models through the following API endpoints.
| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
+| GLM 4.7 | glm-4.7-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` |
| Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` |
| GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@@ -110,6 +111,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
| --------------------------------- | ------ | ------ | ----------- | ------------ |
| Big Pickle | Free | Free | Free | - |
| Grok Code Fast 1 | Free | Free | Free | - |
+| GLM 4.7 | Free | Free | Free | - |
| GLM 4.6 | $0.60 | $2.20 | $0.10 | - |
| Kimi K2 | $0.40 | $2.50 | - | - |
| Kimi K2 Thinking | $0.40 | $2.50 | - | - |
diff --git a/script/publish-start.ts b/script/publish-start.ts
index 229435ddf..a846df14d 100755
--- a/script/publish-start.ts
+++ b/script/publish-start.ts
@@ -17,16 +17,9 @@ if (!Script.preview) {
.then((data: any) => data.version)
const log =
- await $`git log v${previous}..HEAD --oneline --format="%h %s" -- packages/opencode packages/sdk packages/plugin packages/tauri packages/desktop`.text()
+ await $`git log v${previous}..HEAD --oneline --format="%h %s" -- packages/opencode packages/sdk packages/plugin packages/desktop packages/app`.text()
- const commits = log
- .split("\n")
- .filter((line) => line && !line.match(/^\w+ (ignore:|test:|chore:|ci:)/i))
- .join("\n")
-
- const opencode = await createOpencode()
- const session = await opencode.client.session.create()
- console.log("generating changelog since " + previous)
+ const commits = log.split("\n").filter((line) => line && !line.match(/^\w+ (ignore:|test:|chore:|ci:)/i))
const team = [
"actions-user",
@@ -41,20 +34,25 @@ if (!Script.preview) {
"opencode-agent[bot]",
]
- const raw = await opencode.client.session
- .prompt({
- path: {
- id: session.data!.id,
- },
- body: {
- model: {
- providerID: "opencode",
- modelID: "gemini-3-flash",
+ async function generateChangelog() {
+ const opencode = await createOpencode()
+ const session = await opencode.client.session.create()
+ console.log("generating changelog since " + previous)
+
+ const raw = await opencode.client.session
+ .prompt({
+ path: {
+ id: session.data!.id,
},
- parts: [
- {
- type: "text",
- text: `
+ body: {
+ model: {
+ providerID: "opencode",
+ modelID: "gemini-3-flash",
+ },
+ parts: [
+ {
+ type: "text",
+ text: `
Analyze these commits and generate a changelog of all notable user facing changes, grouped by area.
Each commit below includes:
@@ -62,11 +60,11 @@ if (!Script.preview) {
- [areas: ...] showing which areas of the codebase were modified
Commits between ${previous} and HEAD:
- ${commits}
+ ${commits.join("\n")}
Group the changes into these categories based on the [areas: ...] tags (omit any category with no changes):
- **TUI**: Changes to "opencode" area (the terminal/CLI interface)
- - **Desktop**: Changes to "desktop" or "tauri" areas (the desktop application)
+ - **Desktop**: Changes to "app" or "tauri" areas (the desktop application)
- **SDK**: Changes to "sdk" or "plugin" areas (the SDK and plugin system)
- **Extensions**: Changes to "extensions/zed", "extensions/vscode", or "github" areas (editor extensions and GitHub Action)
- **Other**: Any user-facing changes that don't fit the above categories
@@ -105,20 +103,34 @@ if (!Script.preview) {
- Added OIDC_BASE_URL support for custom GitHub App installations (@elithrar)
`,
- },
- ],
- },
- })
- .then((x) => x.data?.parts?.find((y) => y.type === "text")?.text)
- for (const line of raw?.split("\n") ?? []) {
- if (line.startsWith("- ")) {
- notes.push(line)
+ },
+ ],
+ },
+ })
+ .then((x) => x.data?.parts?.find((y) => y.type === "text")?.text)
+ opencode.server.close()
+ return raw
+ }
+
+ const timeout = new Promise((resolve) => setTimeout(() => resolve(null), 120_000))
+ const raw = await Promise.race([generateChangelog(), timeout])
+
+ if (raw) {
+ for (const line of raw.split("\n")) {
+ if (line.startsWith("- ")) {
+ notes.push(line)
+ }
+ }
+ console.log("---- Generated Changelog ----")
+ console.log(notes.join("\n"))
+ console.log("-----------------------------")
+ } else {
+ console.log("Changelog generation timed out, using raw commits")
+ for (const commit of commits) {
+ const message = commit.replace(/^\w+ /, "")
+ notes.push(`- ${message}`)
}
}
- console.log("---- Generated Changelog ----")
- console.log(notes.join("\n"))
- console.log("-----------------------------")
- opencode.server.close()
const compare =
await $`gh api "/repos/sst/opencode/compare/v${previous}...HEAD" --jq '.commits[] | {login: .author.login, message: .commit.message}'`.text()
diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json
index be3139886..791533d63 100644
--- a/sdks/vscode/package.json
+++ b/sdks/vscode/package.json
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
- "version": "1.0.186",
+ "version": "1.0.191",
"publisher": "sst-dev",
"repository": {
"type": "git",
diff --git a/sdks/vscode/src/extension.ts b/sdks/vscode/src/extension.ts
index 63d8d332e..105ab0293 100644
--- a/sdks/vscode/src/extension.ts
+++ b/sdks/vscode/src/extension.ts
@@ -35,7 +35,7 @@ export function activate(context: vscode.ExtensionContext) {
if (terminal.name === TERMINAL_NAME) {
// @ts-ignore
const port = terminal.creationOptions.env?.["_EXTENSION_OPENCODE_PORT"]
- port ? await appendPrompt(parseInt(port), fileRef) : terminal.sendText(fileRef)
+ port ? await appendPrompt(parseInt(port), fileRef) : terminal.sendText(fileRef, false)
terminal.show()
}
})
diff --git a/sst-env.d.ts b/sst-env.d.ts
index 2c182ec35..813d654a0 100644
--- a/sst-env.d.ts
+++ b/sst-env.d.ts
@@ -148,6 +148,10 @@ declare module "sst" {
"name": string
"type": "sst.cloudflare.Bucket"
}
+ "ZenDataNew": {
+ "name": string
+ "type": "sst.cloudflare.Bucket"
+ }
}
}
///