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/bun.lock b/bun.lock
index dee942825..11099e1ed 100644
--- a/bun.lock
+++ b/bun.lock
@@ -27,9 +27,57 @@
"turbo": "2.5.6",
},
},
+ "packages/app": {
+ "name": "@opencode-ai/app",
+ "version": "1.0.191",
+ "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": "catalog:",
+ "solid-js": "catalog:",
+ "solid-list": "catalog:",
+ "tailwindcss": "catalog:",
+ "virtua": "catalog:",
+ "zod": "catalog:",
+ },
+ "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:",
+ },
+ },
"packages/console/app": {
"name": "@opencode-ai/console-app",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -57,7 +105,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -84,7 +132,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -108,7 +156,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -132,55 +180,34 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
- "version": "1.0.190",
+ "version": "1.0.191",
"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",
+ "@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:",
- "solid-list": "catalog:",
- "tailwindcss": "catalog:",
- "virtua": "catalog:",
- "zod": "catalog:",
},
"devDependencies": {
- "@happy-dom/global-registrator": "20.0.11",
- "@tailwindcss/vite": "catalog:",
- "@tsconfig/bun": "1.0.9",
+ "@actions/artifact": "4.0.0",
+ "@tauri-apps/cli": "^2",
"@types/bun": "catalog:",
- "@types/luxon": "catalog:",
- "@types/node": "catalog:",
"@typescript/native-preview": "catalog:",
- "typescript": "catalog:",
+ "typescript": "~5.6.2",
"vite": "catalog:",
- "vite-plugin-icons-spritesheet": "3.0.1",
- "vite-plugin-solid": "catalog:",
},
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@opencode-ai/ui": "workspace:*",
"@opencode-ai/util": "workspace:*",
@@ -209,7 +236,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -225,7 +252,7 @@
},
"packages/opencode": {
"name": "opencode",
- "version": "1.0.190",
+ "version": "1.0.191",
"bin": {
"opencode": "./bin/opencode",
},
@@ -319,7 +346,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -339,7 +366,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
- "version": "1.0.190",
+ "version": "1.0.191",
"devDependencies": {
"@hey-api/openapi-ts": "0.88.1",
"@tsconfig/node22": "catalog:",
@@ -350,7 +377,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -361,36 +388,9 @@
"typescript": "catalog:",
},
},
- "packages/tauri": {
- "name": "@opencode-ai/tauri",
- "version": "1.0.190",
- "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.190",
+ "version": "1.0.191",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -406,7 +406,7 @@
"marked": "16.2.0",
"marked-shiki": "1.2.1",
"remeda": "catalog:",
- "shiki": "3.9.2",
+ "shiki": "catalog:",
"solid-js": "catalog:",
"solid-list": "catalog:",
"virtua": "catalog:",
@@ -425,7 +425,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"zod": "catalog:",
},
@@ -436,7 +436,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
- "version": "1.0.190",
+ "version": "1.0.191",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -455,7 +455,7 @@
"marked-shiki": "1.2.1",
"rehype-autolink-headings": "7.1.0",
"remeda": "catalog:",
- "shiki": "3.4.2",
+ "shiki": "catalog:",
"solid-js": "catalog:",
"toolbeam-docs-theme": "0.4.8",
},
@@ -484,7 +484,7 @@
"@kobalte/core": "0.13.11",
"@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
- "@pierre/diffs": "1.0.0-beta.3",
+ "@pierre/diffs": "1.0.2",
"@solid-primitives/storage": "4.3.3",
"@solidjs/meta": "0.29.4",
"@solidjs/router": "0.15.4",
@@ -503,6 +503,7 @@
"hono-openapi": "1.1.2",
"luxon": "3.6.1",
"remeda": "2.26.0",
+ "shiki": "3.20.0",
"solid-js": "1.9.10",
"solid-list": "0.3.0",
"tailwindcss": "4.1.11",
@@ -1148,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"],
@@ -1172,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"],
@@ -1316,7 +1317,7 @@
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
- "@pierre/diffs": ["@pierre/diffs@1.0.0-beta.3", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/engine-javascript": "3.19.0", "@shikijs/transformers": "3.19.0", "diff": "8.0.2", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "3.19.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-W3dFWdFOBZ9OskGSOgN16aci8dsUyAavCxz3ZvbbVLTb2qRzMZ7H90qdfON13/N2l1HTyh84lkrCs1/sDvnRjQ=="],
+ "@pierre/diffs": ["@pierre/diffs@1.0.2", "", { "dependencies": { "@shikijs/core": "^3.0.0", "@shikijs/engine-javascript": "3.19.0", "@shikijs/transformers": "3.19.0", "diff": "8.0.2", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "3.19.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-RkFSDD5X/U+8QjyilPViYGJfmJNWXR17zTL8zw48+DcVC1Ujbh6I1edyuRnFfgRzpft05x2DSCkz2cjoIAxPvQ=="],
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
@@ -1452,13 +1453,13 @@
"@shikijs/core": ["@shikijs/core@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3q/mzmw09B2B6PgFNeiaN8pkNOixWS726IHmJEpjDAcneDPMQmUg2cweT9cWXY4XcyQS3i6mOOUgQz9RRUP6HA=="],
- "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-kUTRVKPsB/28H5Ko6qEsyudBiWEDLst+Sfi+hwr59E0GLHV0h8RfgbQU7fdN5Lt9A8R1ulRiZyTvAizkROjwDA=="],
+ "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg=="],
- "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-Vn/w5oyQ6TUgTVDIC/BrpXwIlfK6V6kGWDVVz2eRkF2v13YoENUvaNwxMsQU/t6oCuZKzqp9vqtEtEzKl9VegA=="],
+ "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ=="],
- "@shikijs/langs": ["@shikijs/langs@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2" } }, "sha512-X1Q6wRRQXY7HqAuX3I8WjMscjeGjqXCg/Sve7J2GWFORXkSrXud23UECqTBIdCSNKJioFtmUGJQNKtlMMZMn0w=="],
+ "@shikijs/langs": ["@shikijs/langs@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA=="],
- "@shikijs/themes": ["@shikijs/themes@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2" } }, "sha512-6z5lBPBMRfLyyEsgf6uJDHPa6NAGVzFJqH4EAZ+03+7sedYir2yJBRu2uPZOKmj43GyhVHWHvyduLDAwJQfDjA=="],
+ "@shikijs/themes": ["@shikijs/themes@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ=="],
"@shikijs/transformers": ["@shikijs/transformers@3.9.2", "", { "dependencies": { "@shikijs/core": "3.9.2", "@shikijs/types": "3.9.2" } }, "sha512-MW5hT4TyUp6bNAgTExRYLk1NNasVQMTCw1kgbxHcEC0O5cbepPWaB+1k+JzW9r3SP2/R8kiens8/3E6hGKfgsA=="],
@@ -2068,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=="],
@@ -3438,7 +3439,7 @@
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
- "shiki": ["shiki@3.9.2", "", { "dependencies": { "@shikijs/core": "3.9.2", "@shikijs/engine-javascript": "3.9.2", "@shikijs/engine-oniguruma": "3.9.2", "@shikijs/langs": "3.9.2", "@shikijs/themes": "3.9.2", "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-t6NKl5e/zGTvw/IyftLcumolgOczhuroqwXngDeMqJ3h3EQiTY/7wmfgPlsmloD8oYfqkEDqxiaH37Pjm1zUhQ=="],
+ "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="],
"shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="],
@@ -3982,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=="],
@@ -4028,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=="],
@@ -4102,23 +4107,21 @@
"@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=="],
"@opencode-ai/web/marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
- "@opencode-ai/web/shiki": ["shiki@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/engine-javascript": "3.4.2", "@shikijs/engine-oniguruma": "3.4.2", "@shikijs/langs": "3.4.2", "@shikijs/themes": "3.4.2", "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ=="],
-
"@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
"@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.9", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.1" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.8" }, "optionalPeers": ["solid-js"] }, "sha512-pCnxWrciluXCeli/dj5PIEHgbNzim3evtTn12snjqqg8QZWJNMjH1AWIp4iG/tbVjqQ72aBEymMSagvmgxubXw=="],
"@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="],
- "@pierre/diffs/@shikijs/core": ["@shikijs/core@3.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/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="],
"@pierre/diffs/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-ZfWJNm2VMhKkQIKT9qXbs76RRcT0SF/CAvEz0+RkpUDAoDaCx0uFdCGzSRiD9gSlhm6AHkjdieOBJMaO2eC1rQ=="],
@@ -4132,6 +4135,14 @@
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
+ "@shikijs/engine-javascript/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
+
+ "@shikijs/engine-oniguruma/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
+
+ "@shikijs/langs/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
+
+ "@shikijs/themes/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
+
"@slack/bolt/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
"@slack/oauth/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="],
@@ -4208,8 +4219,6 @@
"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=="],
@@ -4228,6 +4237,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=="],
@@ -4342,6 +4353,10 @@
"sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+ "shiki/@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="],
+
+ "shiki/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
+
"sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
@@ -4378,8 +4393,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=="],
-
"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=="],
@@ -4686,32 +4699,24 @@
"@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=="],
"@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="],
- "@opencode-ai/web/shiki/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="],
-
- "@opencode-ai/web/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-1/adJbSMBOkpScCE/SB6XkjJU17ANln3Wky7lOmrnpl+zBdQ1qXUJg2GXTYVHRq+2j3hd1DesmElTXYDgtfSOQ=="],
-
- "@opencode-ai/web/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-zcZKMnNndgRa3ORja6Iemsr3DrLtkX3cAF7lTJkdMB6v9alhlBsX9uNiCpqofNrXOvpA3h6lHcLJxgCIhVOU5Q=="],
-
- "@opencode-ai/web/shiki/@shikijs/langs": ["@shikijs/langs@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2" } }, "sha512-H6azIAM+OXD98yztIfs/KH5H4PU39t+SREhmM8LaNXyUrqj2mx+zVkr8MWYqjceSjDw9I1jawm1WdFqU806rMA=="],
-
- "@opencode-ai/web/shiki/@shikijs/themes": ["@shikijs/themes@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2" } }, "sha512-qAEuAQh+brd8Jyej2UDDf+b4V2g1Rm8aBIdvt32XhDPrHvDkEnpb7Kzc9hSuHUxz0Iuflmq7elaDuQAP9bHIhg=="],
-
- "@opencode-ai/web/shiki/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="],
-
"@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
- "@pierre/diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="],
+ "@pierre/diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
"@pierre/diffs/@shikijs/engine-javascript/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="],
+ "@pierre/diffs/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="],
+
"@pierre/diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="],
+ "@pierre/diffs/shiki/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="],
+
"@pierre/diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1hRxtYIJfJSZeM5ivbUXv9hcJP3PWRo5prG/V2sWwiubUKTa+7P62d2qxCW8jiVFX4pgRHhnHNp+qeR7Xl+6kg=="],
"@pierre/diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-dBMFzzg1QiXqCVQ5ONc0z2ebyoi5BKz+MtfByLm0o5/nbUu3Iz8uaTCa5uzGiscQKm7lVShfZHU1+OG3t5hgwg=="],
@@ -5046,7 +5051,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=="],
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 8ca9dd5dd..dbf753171 100644
--- a/nix/hashes.json
+++ b/nix/hashes.json
@@ -1,3 +1,3 @@
{
- "nodeModules": "sha256-brPDbHqdp4/U8AIXtp75uDRI6K3e2FH2b7V/QNb07us="
+ "nodeModules": "sha256-QlQblkUq49DOdvNNMNAzHHAfHxR6cZNmJtyzc4rD168="
}
diff --git a/package.json b/package.json
index 3134cc976..23ef2253a 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"@tsconfig/bun": "1.0.9",
"@cloudflare/workers-types": "4.20251008.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
- "@pierre/diffs": "1.0.0-beta.3",
+ "@pierre/diffs": "1.0.2",
"@solid-primitives/storage": "4.3.3",
"@tailwindcss/vite": "4.1.11",
"diff": "8.0.2",
@@ -44,6 +44,7 @@
"@typescript/native-preview": "7.0.0-dev.20251207.1",
"zod": "4.1.8",
"remeda": "2.26.0",
+ "shiki": "3.20.0",
"solid-list": "0.3.0",
"tailwindcss": "4.1.11",
"virtua": "0.42.3",
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..9280bec2b
--- /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": "catalog:",
+ "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 100%
rename from packages/desktop/src/components/header.tsx
rename to packages/app/src/components/header.tsx
diff --git a/packages/desktop/src/components/link.tsx b/packages/app/src/components/link.tsx
similarity index 100%
rename from packages/desktop/src/components/link.tsx
rename to packages/app/src/components/link.tsx
diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx
similarity index 100%
rename from packages/desktop/src/components/prompt-input.tsx
rename to packages/app/src/components/prompt-input.tsx
diff --git a/packages/desktop/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx
similarity index 100%
rename from packages/desktop/src/components/session-context-usage.tsx
rename to packages/app/src/components/session-context-usage.tsx
diff --git a/packages/desktop/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx
similarity index 100%
rename from packages/desktop/src/components/terminal.tsx
rename to packages/app/src/components/terminal.tsx
diff --git a/packages/desktop/src/context/command.tsx b/packages/app/src/context/command.tsx
similarity index 100%
rename from packages/desktop/src/context/command.tsx
rename to packages/app/src/context/command.tsx
diff --git a/packages/desktop/src/context/global-sdk.tsx b/packages/app/src/context/global-sdk.tsx
similarity index 100%
rename from packages/desktop/src/context/global-sdk.tsx
rename to packages/app/src/context/global-sdk.tsx
diff --git a/packages/desktop/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx
similarity index 97%
rename from packages/desktop/src/context/global-sync.tsx
rename to packages/app/src/context/global-sync.tsx
index 27a89e7bc..ae40555d6 100644
--- a/packages/desktop/src/context/global-sync.tsx
+++ b/packages/app/src/context/global-sync.tsx
@@ -295,6 +295,15 @@ function createGlobalSync() {
})
async function bootstrap() {
+ const health = await globalSDK.client.global.health().then((x) => 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 100%
rename from packages/desktop/src/context/layout.tsx
rename to packages/app/src/context/layout.tsx
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 100%
rename from packages/desktop/src/pages/session.tsx
rename to packages/app/src/pages/session.tsx
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 aeb5fe2b2..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.190",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
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 cf2eb502a..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.190",
+ "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 be09677ea..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.190",
+ "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 3b43f7653..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.190",
+ "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 7665f6d0c..23eab7f4d 100644
--- a/packages/desktop/package.json
+++ b/packages/desktop/package.json
@@ -1,62 +1,37 @@
{
"name": "@opencode-ai/desktop",
- "version": "1.0.190",
- "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 08a9fa517..3df50aff2 100644
--- a/packages/enterprise/package.json
+++ b/packages/enterprise/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
- "version": "1.0.190",
+ "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 2e144191a..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.190"
+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.190/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.190/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.190/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.190/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.190/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 3bd83040e..83de02f9d 100644
--- a/packages/function/package.json
+++ b/packages/function/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
- "version": "1.0.190",
+ "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 3fb30f37c..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.190",
+ "version": "1.0.191",
"name": "opencode",
"type": "module",
"private": true,
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 71937e179..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() {
@@ -881,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 098ee83cc..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,124 +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
-
-
- Parent {keybind.print("session_parent")}
-
-
- 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 029a012f8..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
@@ -961,7 +964,7 @@ export function Session() {
-
+
-
+
-
+
+
+ setSidebar("hide")}
+ >
+ e.stopPropagation()}>
+
+
+
+
)
@@ -1646,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}"
@@ -1695,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/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/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/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 e1edfdf51..339ba2f42 100644
--- a/packages/opencode/src/session/compaction.ts
+++ b/packages/opencode/src/session/compaction.ts
@@ -130,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,
@@ -150,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 748851b4f..fabe3fa51 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -583,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/skill/skill.ts b/packages/opencode/src/skill/skill.ts
index 888460e84..41df88f8b 100644
--- a/packages/opencode/src/skill/skill.ts
+++ b/packages/opencode/src/skill/skill.ts
@@ -3,8 +3,10 @@ import { Config } from "../config/config"
import { Instance } from "../project/instance"
import { NamedError } from "@opencode-ai/util/error"
import { ConfigMarkdown } from "../config/markdown"
+import { Log } from "../util/log"
export namespace Skill {
+ const log = Log.create({ service: "skill" })
export const Info = z.object({
name: z.string(),
description: z.string(),
@@ -50,6 +52,16 @@ export namespace Skill {
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,
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 52d8e2cbb..69a45432d 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -115,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
@@ -130,7 +130,7 @@ export namespace ToolRegistry {
using _ = log.time(t.id)
return {
id: t.id,
- ...(await t.init()),
+ ...(await t.init({ agent })),
}
}),
)
diff --git a/packages/opencode/src/tool/skill.ts b/packages/opencode/src/tool/skill.ts
index ad5001da9..2503f7639 100644
--- a/packages/opencode/src/tool/skill.ts
+++ b/packages/opencode/src/tool/skill.ts
@@ -7,78 +7,94 @@ import { Permission } from "../permission"
import { Wildcard } from "../util/wildcard"
import { ConfigMarkdown } from "../config/markdown"
-export const SkillTool = Tool.define("skill", async () => {
- const skills = await Skill.all()
- 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.",
- "",
- ...skills.flatMap((skill) => [
- ` `,
- ` ${skill.name}`,
- ` ${skill.description}`,
- ` `,
- ]),
- "",
- ].join(" "),
- parameters: z.object({
- name: z
- .string()
- .describe("The skill identifier from available_skills (e.g., 'code-review' or 'category/helper')"),
- }),
- async execute(params, ctx) {
- const agent = await Agent.get(ctx.agent)
-
- const skill = await Skill.get(params.name)
-
- if (!skill) {
- const available = Skill.all().then((x) => Object.keys(x).join(", "))
- throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`)
- }
-
- // Check permission using Wildcard.all on the skill ID
- 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: { id: params.name, 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,
- },
- }
- },
- }
+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/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 330d74b39..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.190",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
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 a85bad961..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.190",
+ "version": "1.0.191",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
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 403f1d6a0..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
@@ -1897,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 24aea70a8..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"
},
diff --git a/packages/slack/package.json b/packages/slack/package.json
index 26cefb725..4be3b2ef1 100644
--- a/packages/slack/package.json
+++ b/packages/slack/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
- "version": "1.0.190",
+ "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 1db8ec12c..000000000
--- a/packages/tauri/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "@opencode-ai/tauri",
- "private": true,
- "version": "1.0.190",
- "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 d051239d0..214d0b3a6 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
- "version": "1.0.190",
+ "version": "1.0.191",
"type": "module",
"exports": {
"./*": "./src/components/*.tsx",
@@ -47,7 +47,7 @@
"marked": "16.2.0",
"marked-shiki": "1.2.1",
"remeda": "catalog:",
- "shiki": "3.9.2",
+ "shiki": "catalog:",
"solid-js": "catalog:",
"solid-list": "catalog:",
"virtua": "catalog:"
diff --git a/packages/util/package.json b/packages/util/package.json
index 86405908e..9194b1e9f 100644
--- a/packages/util/package.json
+++ b/packages/util/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/util",
- "version": "1.0.190",
+ "version": "1.0.191",
"private": true,
"type": "module",
"exports": {
diff --git a/packages/web/package.json b/packages/web/package.json
index 4ce1b359e..191e3e594 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/web",
"type": "module",
- "version": "1.0.190",
+ "version": "1.0.191",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
@@ -28,7 +28,7 @@
"marked-shiki": "1.2.1",
"rehype-autolink-headings": "7.1.0",
"remeda": "catalog:",
- "shiki": "3.4.2",
+ "shiki": "catalog:",
"solid-js": "catalog:",
"toolbeam-docs-theme": "0.4.8"
},
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/script/publish-start.ts b/script/publish-start.ts
index 9213e1352..a846df14d 100755
--- a/script/publish-start.ts
+++ b/script/publish-start.ts
@@ -17,7 +17,7 @@ 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))
@@ -64,7 +64,7 @@ if (!Script.preview) {
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
diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json
index a80b5eb54..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.190",
+ "version": "1.0.191",
"publisher": "sst-dev",
"repository": {
"type": "git",
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"
+ }
}
}
///