diff options
58 files changed, 910 insertions, 320 deletions
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 90d440641..d94f7f48d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -17,7 +17,7 @@ jobs: - uses: oven-sh/setup-bun@v1 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - run: bun install diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 11ecc93fd..2927dd1b1 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -22,7 +22,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v1 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - name: run run: | diff --git a/.github/workflows/publish-vscode.yml b/.github/workflows/publish-vscode.yml index f40c93798..bff8c192b 100644 --- a/.github/workflows/publish-vscode.yml +++ b/.github/workflows/publish-vscode.yml @@ -21,7 +21,7 @@ jobs: - uses: oven-sh/setup-bun@v2 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - run: git fetch --force --tags - run: bun install -g @vscode/vsce diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 310ce162c..c10957a1b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,16 +37,16 @@ jobs: - uses: oven-sh/setup-bun@v2 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - name: Cache ~/.bun id: cache-bun uses: actions/cache@v3 with: path: ~/.bun - key: ${{ runner.os }}-bun-1-2-21-${{ hashFiles('bun.lock') }} + key: ${{ runner.os }}-bun-1-3-0-${{ hashFiles('bun.lock') }} restore-keys: | - ${{ runner.os }}-bun-1-2-21- + ${{ runner.os }}-bun-1-3-0- - name: Install makepkg run: | diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 0cc6faf7f..ddb095354 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -26,16 +26,16 @@ jobs: - uses: oven-sh/setup-bun@v2 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - name: Cache ~/.bun id: cache-bun uses: actions/cache@v3 with: path: ~/.bun - key: ${{ runner.os }}-bun-1-2-21-${{ hashFiles('bun.lock') }} + key: ${{ runner.os }}-bun-1-3-0-${{ hashFiles('bun.lock') }} restore-keys: | - ${{ runner.os }}-bun-1-2-21- + ${{ runner.os }}-bun-1-3-0- - name: Install dependencies run: bun install diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 73516f2ec..441f9585f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v1 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - name: run run: | diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index e80896566..3854644b6 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v1 with: - bun-version: 1.2.21 + bun-version: 1.3.0 - name: Install dependencies run: bun install diff --git a/.opencode/command/spellcheck.md b/.opencode/command/spellcheck.md new file mode 100644 index 000000000..afa1970b7 --- /dev/null +++ b/.opencode/command/spellcheck.md @@ -0,0 +1,5 @@ +--- +description: Spellcheck all markdown file changes +--- + +Look at all the unstaged changes to markdown (.md, .mdx) files, pull out the lines that have changed, and check for spelling and grammar errors. @@ -103,3 +103,5 @@ | 2025-10-06 | 460,927 (+5,368) | 379,489 (+4,744) | 840,416 (+10,112) | | 2025-10-07 | 467,336 (+6,409) | 385,438 (+5,949) | 852,774 (+12,358) | | 2025-10-08 | 474,643 (+7,307) | 394,139 (+8,701) | 868,782 (+16,008) | +| 2025-10-09 | 479,203 (+4,560) | 400,526 (+6,387) | 879,729 (+10,947) | +| 2025-10-10 | 484,374 (+5,171) | 406,015 (+5,489) | 890,389 (+10,660) | @@ -4,6 +4,7 @@ "": { "name": "opencode", "devDependencies": { + "@tsconfig/bun": "1.0.9", "husky": "9.1.7", "prettier": "3.6.2", "sst": "3.17.13", @@ -21,14 +22,13 @@ "@solidjs/meta": "^0.29.4", "@solidjs/router": "^0.15.0", "@solidjs/start": "^1.1.0", - "solid-js": "catalog:", "vinxi": "^0.5.7", "zod": "catalog:", }, }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -40,27 +40,35 @@ "postgres": "3.4.7", "stripe": "18.0.0", "ulid": "3.0.0", + "zod": "catalog:", }, "devDependencies": { + "@cloudflare/workers-types": "4.20251008.0", + "@tsconfig/node22": "22.0.2", + "@types/bun": "1.3.0", + "@types/node": "24.7.1", "drizzle-kit": "0.30.5", "mysql2": "3.14.4", }, }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", "@ai-sdk/openai-compatible": "1.0.1", "@hono/zod-validator": "catalog:", "@openauthjs/openauth": "0.0.0-20250322224806", + "@opencode-ai/console-core": "workspace:*", + "@opencode-ai/console-resource": "workspace:*", "ai": "catalog:", "hono": "catalog:", "zod": "catalog:", }, "devDependencies": { - "@cloudflare/workers-types": "4.20250522.0", + "@cloudflare/workers-types": "4.20251008.0", + "@tsconfig/node22": "22.0.2", "@types/node": "catalog:", "openai": "5.11.0", "typescript": "catalog:", @@ -68,10 +76,11 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", + "@tsconfig/bun": "1.0.9", "@types/react": "18.0.25", "react": "18.2.0", }, @@ -81,17 +90,20 @@ "dependencies": { "@cloudflare/workers-types": "^4.20250830.0", }, + "devDependencies": { + "@tsconfig/node22": "22.0.2", + }, }, "packages/console/scripts": { "name": "@opencode-ai/console-scripts", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@opencode-ai/console-core": "workspace:*", }, }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -108,13 +120,13 @@ "marked-shiki": "1.2.1", "remeda": "catalog:", "shiki": "3.9.2", - "solid-js": "catalog:", "solid-list": "0.3.0", "tailwindcss": "4.1.11", "virtua": "0.42.3", }, "devDependencies": { "@tailwindcss/vite": "4.1.11", + "@tsconfig/bun": "1.0.9", "@types/luxon": "3.7.1", "@types/node": "catalog:", "typescript": "catalog:", @@ -125,7 +137,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -140,7 +152,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "0.14.6", + "version": "0.14.7", "bin": { "opencode": "./bin/opencode", }, @@ -152,6 +164,7 @@ "@openauthjs/openauth": "0.4.3", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/sdk": "workspace:*", + "@parcel/watcher": "2.5.1", "@standard-schema/spec": "1.0.0", "@zip.js/zip.js": "2.7.62", "ai": "catalog:", @@ -181,6 +194,7 @@ "@ai-sdk/amazon-bedrock": "2.2.10", "@ai-sdk/google-vertex": "3.0.16", "@octokit/webhooks-types": "7.6.1", + "@parcel/watcher-win32-x64": "2.5.1", "@standard-schema/spec": "1.0.0", "@tsconfig/bun": "1.0.7", "@types/bun": "catalog:", @@ -193,31 +207,30 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", }, "devDependencies": { "@tsconfig/node22": "catalog:", + "@types/node": "24.7.1", "typescript": "catalog:", }, }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "0.14.6", - "dependencies": { - "@hey-api/openapi-ts": "0.81.0", - }, + "version": "0.14.7", "devDependencies": { - "@hey-api/openapi-ts": "0.80.1", + "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", + "@types/node": "24.7.1", "typescript": "catalog:", }, }, "packages/web": { "name": "@opencode-ai/web", - "version": "0.14.6", + "version": "0.14.7", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -239,7 +252,7 @@ "sharp": "0.32.5", "shiki": "3.4.2", "solid-js": "catalog:", - "toolbeam-docs-theme": "0.4.7", + "toolbeam-docs-theme": "0.4.8", }, "devDependencies": { "@types/node": "catalog:", @@ -255,11 +268,14 @@ "web-tree-sitter", "tree-sitter-bash", ], + "overrides": { + "@types/bun": "catalog:", + }, "catalog": { "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@tsconfig/node22": "22.0.2", - "@types/bun": "1.2.21", + "@types/bun": "1.3.0", "@types/node": "22.13.9", "ai": "5.0.8", "fuzzysort": "3.1.0", @@ -453,7 +469,7 @@ "@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-+m124IiM149QvvzAOrO766uTdILqXJZqzZjqTaMTaWXegjjsJwGSL6v9d71TSFntEwxeXnpJPBkVWyKZFjqrvg=="], - "@cloudflare/workers-types": ["@cloudflare/[email protected]", "", {}, "sha512-9RIffHobc35JWeddzBguGgPa4wLDr5x5F94+0/qy7LiV6pTBQ/M5qGEN9VA16IDT3EUpYI0WKh6VpcmeVEtVtw=="], + "@cloudflare/workers-types": ["@cloudflare/[email protected]", "", {}, "sha512-dZLkO4PbCL0qcCSKzuW7KE4GYe49lI12LCfQ5y9XeSwgYBoAUbwH4gmJ6A0qUIURiTJTkGkRkhVPqpq2XNgYRA=="], "@corvu/utils": ["@corvu/[email protected]", "", { "dependencies": { "@floating-ui/dom": "^1.6.11" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA=="], @@ -553,7 +569,7 @@ "@hey-api/json-schema-ref-parser": ["@hey-api/[email protected]", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0", "lodash": "^4.17.21" } }, "sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w=="], - "@hey-api/openapi-ts": ["@hey-api/[email protected]", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-AC478kg36vmmrseLZNFonZ/cmXXmDzW5yWz4PVg1S8ebJsRtVRJ/QU+mtnXfzf9avN2P0pz/AO4WAe4jyFY2gA=="], + "@hey-api/openapi-ts": ["@hey-api/[email protected]", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "js-yaml": "4.1.0", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-PoJukNBkUfHOoMDpN33bBETX49TUhy7Hu8Sa0jslOvFndvZ5VjQr4Nl/Dzjb9LG1Lp5HjybyTJMA6a1zYk/q6A=="], "@hono/standard-validator": ["@hono/[email protected]", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-EIyZPPwkyLn6XKwFj5NBEWHXhXbgmnVh2ceIFo5GO7gKI9WmzTjPDKnppQB0KrqKeAkq3kpoW4SIbu5X1dgx3w=="], @@ -1141,7 +1157,7 @@ "@thisbeyond/solid-dnd": ["@thisbeyond/[email protected]", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="], - "@tsconfig/bun": ["@tsconfig/[email protected]", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], + "@tsconfig/bun": ["@tsconfig/[email protected]", "", {}, "sha512-4M0/Ivfwcpz325z6CwSifOBZYji3DFOEpY6zEUt0+Xi2qRhzwvmqQN9XAHJh3OVvRJuAqVTLU2abdCplvp6mwQ=="], "@tsconfig/node22": ["@tsconfig/[email protected]", "", {}, "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA=="], @@ -1155,7 +1171,7 @@ "@types/braces": ["@types/[email protected]", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], - "@types/bun": ["@types/[email protected]", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], + "@types/bun": ["@types/[email protected]", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="], "@types/debug": ["@types/[email protected]", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], @@ -1183,7 +1199,7 @@ "@types/nlcst": ["@types/[email protected]", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="], - "@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q=="], "@types/prop-types": ["@types/[email protected]", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], @@ -1369,7 +1385,7 @@ "buffer-from": ["[email protected]", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bun-types": ["[email protected]", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], + "bun-types": ["[email protected]", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="], "bundle-name": ["[email protected]", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], @@ -2797,7 +2813,7 @@ "toidentifier": ["[email protected]", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - "toolbeam-docs-theme": ["[email protected]", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-oVA/V4M4s4vtLljfnZrOSuCNomek5h9jIYkr92l4QgAQvB3ht+D7xAJIy27IGVJzYA5scUE1OK84ZZqeajoeWw=="], + "toolbeam-docs-theme": ["[email protected]", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-b+5ynEFp4Woe5a22hzNQm42lD23t13ZMihVxHbzjA50zdcM9aOSJTIjdJ0PDSd4/50HbBXcpHiQsz6rM4N88ww=="], "tr46": ["[email protected]", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], @@ -2857,7 +2873,7 @@ "undici": ["[email protected]", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], - "undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "undici-types": ["[email protected]", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], "unenv": ["[email protected]", "", { "dependencies": { "consola": "^3.2.3", "defu": "^6.1.4", "mime": "^3.0.0", "node-fetch-native": "^1.6.4", "pathe": "^1.1.2" } }, "sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ=="], @@ -3125,14 +3141,20 @@ "@openauthjs/openauth/jose": ["[email protected]", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], - "@opencode-ai/console-resource/@cloudflare/workers-types": ["@cloudflare/[email protected]", "", {}, "sha512-MXseDjmqL1hIdQCqwHDMG8SE60W4FdwqLsofZjo/KtLH9zFcoQfZkCYyQrdfEJINiSoNJjrup7WR6KsqiFUSsg=="], + "@opencode-ai/console-function/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@opencode-ai/desktop/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@opencode-ai/function/@cloudflare/workers-types": ["@cloudflare/[email protected]", "", {}, "sha512-9RIffHobc35JWeddzBguGgPa4wLDr5x5F94+0/qy7LiV6pTBQ/M5qGEN9VA16IDT3EUpYI0WKh6VpcmeVEtVtw=="], - "@opencode-ai/sdk/@hey-api/openapi-ts": ["@hey-api/[email protected]", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "js-yaml": "4.1.0", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-PoJukNBkUfHOoMDpN33bBETX49TUhy7Hu8Sa0jslOvFndvZ5VjQr4Nl/Dzjb9LG1Lp5HjybyTJMA6a1zYk/q6A=="], + "@opencode-ai/function/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], "@opencode-ai/web/@shikijs/transformers": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], "@opencode-ai/web/@types/luxon": ["@types/[email protected]", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="], + "@opencode-ai/web/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@opencode-ai/web/marked": ["[email protected]", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], "@opencode-ai/web/shiki": ["[email protected]", "", { "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=="], @@ -3169,6 +3191,10 @@ "@tanstack/router-utils/pathe": ["[email protected]", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "@types/fontkit/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/sax/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@vercel/nft/estree-walker": ["[email protected]", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "@vercel/nft/glob": ["[email protected]", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -3205,6 +3231,8 @@ "boxen/chalk": ["[email protected]", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "bun-types/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "c12/confbox": ["[email protected]", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "c12/ohash": ["[email protected]", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], @@ -3309,10 +3337,14 @@ "opencode/@openauthjs/openauth": ["@openauthjs/[email protected]", "", { "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-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw=="], + "opencode/@tsconfig/bun": ["@tsconfig/[email protected]", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], + "opencode/ulid": ["[email protected]", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="], "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/[email protected]", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], + "opencontrol/@tsconfig/bun": ["@tsconfig/[email protected]", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], + "opencontrol/hono": ["[email protected]", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="], "opencontrol/zod": ["[email protected]", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], @@ -3383,6 +3415,8 @@ "strip-literal/js-tokens": ["[email protected]", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + "stripe/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "sucrase/commander": ["[email protected]", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "sucrase/glob": ["[email protected]", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -3589,10 +3623,18 @@ "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/[email protected]", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + "@opencode-ai/console-function/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@opencode-ai/desktop/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@opencode-ai/function/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], + "@opencode-ai/web/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@opencode-ai/web/shiki/@shikijs/core": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@opencode-ai/web/shiki/@shikijs/engine-javascript": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-1/adJbSMBOkpScCE/SB6XkjJU17ANln3Wky7lOmrnpl+zBdQ1qXUJg2GXTYVHRq+2j3hd1DesmElTXYDgtfSOQ=="], @@ -3619,6 +3661,10 @@ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/[email protected]", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@types/fontkit/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/sax/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@vercel/nft/glob/jackspeak": ["[email protected]", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "@vercel/nft/glob/minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -3637,6 +3683,8 @@ "bl/buffer/ieee754": ["[email protected]", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "bun-types/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "c12/pkg-types/pathe": ["[email protected]", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "cross-spawn/which/isexe": ["[email protected]", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -3757,6 +3805,8 @@ "string-width-cjs/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "stripe/@types/node/undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "sucrase/glob/jackspeak": ["[email protected]", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "sucrase/glob/minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], diff --git a/package.json b/package.json index e1116503a..abbc89009 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "opencode", "private": true, "type": "module", - "packageManager": "[email protected]", + "packageManager": "[email protected]", "scripts": { "dev": "bun run packages/opencode/src/index.ts", "typecheck": "bun turbo typecheck", @@ -16,7 +16,7 @@ "packages/sdk/js" ], "catalog": { - "@types/bun": "1.2.21", + "@types/bun": "1.3.0", "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@types/node": "22.13.9", @@ -32,6 +32,7 @@ } }, "devDependencies": { + "@tsconfig/bun": "1.0.9", "husky": "9.1.7", "prettier": "3.6.2", "sst": "3.17.13", @@ -56,5 +57,8 @@ ], "patchedDependencies": { "@solidjs/[email protected]": "patches/@solidjs%[email protected]" + }, + "overrides": { + "@types/bun": "catalog:" } } diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 59eb56792..a8f264e53 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "0.14.6" + "version": "0.14.7" }, "dependencies": { "@ibm/plex": "6.4.1", @@ -18,7 +18,6 @@ "@solidjs/meta": "^0.29.4", "@solidjs/router": "^0.15.0", "@solidjs/start": "^1.1.0", - "solid-js": "catalog:", "vinxi": "^0.5.7", "zod": "catalog:" }, diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 13c6991b2..a701dae37 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": "0.14.6", + "version": "0.14.7", "private": true, "type": "module", "dependencies": { @@ -14,7 +14,8 @@ "drizzle-orm": "0.41.0", "postgres": "3.4.7", "stripe": "18.0.0", - "ulid": "3.0.0" + "ulid": "3.0.0", + "zod": "catalog:" }, "exports": { "./*": "./src/*" @@ -29,6 +30,10 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { + "@cloudflare/workers-types": "4.20251008.0", + "@tsconfig/node22": "22.0.2", + "@types/bun": "1.3.0", + "@types/node": "24.7.1", "drizzle-kit": "0.30.5", "mysql2": "3.14.4" } diff --git a/packages/console/core/src/context.ts b/packages/console/core/src/context.ts index c2ca6a313..59594cb4a 100644 --- a/packages/console/core/src/context.ts +++ b/packages/console/core/src/context.ts @@ -14,7 +14,7 @@ export namespace Context { return result }, provide<R>(value: T, fn: () => R) { - return storage.run<R>(value, fn) + return storage.run(value, fn) }, } } diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 40f12b1c2..97e5b8a87 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "0.14.6", + "version": "0.14.7", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", @@ -8,7 +8,8 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@cloudflare/workers-types": "4.20250522.0", + "@cloudflare/workers-types": "4.20251008.0", + "@tsconfig/node22": "22.0.2", "@types/node": "catalog:", "openai": "5.11.0", "typescript": "catalog:" @@ -18,6 +19,8 @@ "@ai-sdk/openai": "2.0.2", "@ai-sdk/openai-compatible": "1.0.1", "@hono/zod-validator": "catalog:", + "@opencode-ai/console-core": "workspace:*", + "@opencode-ai/console-resource": "workspace:*", "@openauthjs/openauth": "0.0.0-20250322224806", "ai": "catalog:", "hono": "catalog:", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 5cdc1c4a8..7b83a7dd7 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,19 +1,20 @@ { - "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-mail", - "version": "0.14.6", - "private": true, - "type": "module", + "version": "0.14.7", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", + "@tsconfig/bun": "1.0.9", "@types/react": "18.0.25", "react": "18.2.0" }, "exports": { "./*": "./emails/templates/*" }, + "$schema": "https://json.schemastore.org/package.json", + "private": true, "scripts": { "dev": "email preview emails/templates" - } + }, + "type": "module" } diff --git a/packages/console/resource/package.json b/packages/console/resource/package.json index 3f5f54ab6..a59aee750 100644 --- a/packages/console/resource/package.json +++ b/packages/console/resource/package.json @@ -11,5 +11,8 @@ }, "import": "./resource.node.ts" } + }, + "devDependencies": { + "@tsconfig/node22": "22.0.2" } } diff --git a/packages/console/scripts/package.json b/packages/console/scripts/package.json index 9259562f5..7c47c433c 100644 --- a/packages/console/scripts/package.json +++ b/packages/console/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-scripts", - "version": "0.14.6", + "version": "0.14.7", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 54173ae0f..5885ad159 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "0.14.6", + "version": "0.14.7", "description": "", "type": "module", "scripts": { @@ -13,6 +13,7 @@ "license": "MIT", "devDependencies": { "@tailwindcss/vite": "4.1.11", + "@tsconfig/bun": "1.0.9", "@types/luxon": "3.7.1", "@types/node": "catalog:", "typescript": "catalog:", @@ -36,7 +37,6 @@ "marked-shiki": "1.2.1", "remeda": "catalog:", "shiki": "3.9.2", - "solid-js": "catalog:", "solid-list": "0.3.0", "tailwindcss": "4.1.11", "virtua": "0.42.3" diff --git a/packages/desktop/tsconfig.json b/packages/desktop/tsconfig.json index d86b8ca46..82541a6d3 100644 --- a/packages/desktop/tsconfig.json +++ b/packages/desktop/tsconfig.json @@ -1,11 +1,18 @@ { "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@tsconfig/bun/tsconfig.json", "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, "jsx": "preserve", "jsxImportSource": "solid-js", - "types": ["vite/client"], - "lib": ["DOM", "DOM.Iterable"], + "allowJs": true, + "strict": true, + "noEmit": true, + "isolatedModules": true, "paths": { "@/*": ["./src/*"] } diff --git a/packages/function/package.json b/packages/function/package.json index 44ee9be2c..fedecd97b 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "0.14.6", + "version": "0.14.7", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index ea83d4e22..c0aa6c8d6 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "0.14.6", + "version": "0.14.7", "name": "opencode", "type": "module", "private": true, @@ -20,6 +20,7 @@ "@ai-sdk/amazon-bedrock": "2.2.10", "@ai-sdk/google-vertex": "3.0.16", "@octokit/webhooks-types": "7.6.1", + "@parcel/watcher-win32-x64": "2.5.1", "@standard-schema/spec": "1.0.0", "@tsconfig/bun": "1.0.7", "@types/bun": "catalog:", @@ -37,6 +38,7 @@ "@openauthjs/openauth": "0.4.3", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/sdk": "workspace:*", + "@parcel/watcher": "2.5.1", "@standard-schema/spec": "1.0.0", "@zip.js/zip.js": "2.7.62", "ai": "catalog:", diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 02090c69f..4c4bc7825 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -1,4 +1,5 @@ #!/usr/bin/env bun +import path from "path" const dir = new URL("..", import.meta.url).pathname process.chdir(dir) import { $ } from "bun" @@ -32,6 +33,12 @@ for (const [os, arch] of targets) { await $`CGO_ENABLED=0 GOOS=${os} GOARCH=${GOARCH[arch]} go build -ldflags="-s -w -X main.Version=${version}" -o ../opencode/dist/${name}/bin/tui ../tui/cmd/opencode/main.go` .cwd("../tui") .quiet() + + const watcher = `@parcel/watcher-${os === "windows" ? "win32" : os}-${arch.replace("-baseline", "")}${os === "linux" ? "-glibc" : ""}` + await $`mkdir -p ../../node_modules/${watcher}` + await $`npm pack npm pack ${watcher}`.cwd(path.join(dir, "../../node_modules")).quiet() + await $`tar -xf ../../node_modules/${watcher.replace("@parcel/", "parcel-")}-*.tgz -C ../../node_modules/${watcher} --strip-components=1` + await Bun.build({ compile: { target: `bun-${os}-${arch}` as any, diff --git a/packages/opencode/src/cli/cmd/export.ts b/packages/opencode/src/cli/cmd/export.ts index 996522b5a..c8825c83d 100644 --- a/packages/opencode/src/cli/cmd/export.ts +++ b/packages/opencode/src/cli/cmd/export.ts @@ -66,7 +66,8 @@ export const ExportCommand = cmd({ })), } - console.log(JSON.stringify(exportData, null, 2)) + process.stdout.write(JSON.stringify(exportData, null, 2)) + process.stdout.write("\n") } catch (error) { UI.error(`Session not found: ${sessionID!}`) process.exit(1) diff --git a/packages/opencode/src/cli/error.ts b/packages/opencode/src/cli/error.ts index fa77ca773..8288de1eb 100644 --- a/packages/opencode/src/cli/error.ts +++ b/packages/opencode/src/cli/error.ts @@ -10,6 +10,8 @@ export function FormatError(input: unknown) { `Config file at ${input.data.path} is not valid JSON(C)` + (input.data.message ? `: ${input.data.message}` : "") ) } + if (Config.DirectoryError.isInstance(input)) + return `Directory "${input.data.dir}" in ${input.data.path} is not valid. Did you mean "${input.data.suggestion}"?` if (Config.InvalidError.isInstance(input)) return [ `Config file at ${input.data.path} is invalid` + (input.data.message ? `: ${input.data.message}` : ""), diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 40e4d90a4..aa785235f 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -15,6 +15,8 @@ import { Auth } from "../auth" import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser" import { Instance } from "../project/instance" import { LSPServer } from "../lsp/server" +import { BunProc } from "@/bun" +import { Installation } from "@/installation" export namespace Config { const log = Log.create({ service: "config" }) @@ -60,7 +62,8 @@ export namespace Config { ] for (const dir of directories) { - await assertValid(dir).catch(() => {}) + await assertValid(dir) + installDependencies(dir) result.command = mergeDeep(result.command ?? {}, await loadCommand(dir)) result.agent = mergeDeep(result.agent, await loadAgent(dir)) result.agent = mergeDeep(result.agent, await loadMode(dir)) @@ -117,26 +120,34 @@ export namespace Config { } }) + const INVALID_DIRS = new Bun.Glob(`{${["agents", "commands", "plugins", "tools"].join(",")}}/`) async function assertValid(dir: string) { - const ALLOWED_DIRS = new Set(["agent", "command", "mode", "plugin", "tool", "themes"]) - const UNEXPECTED_DIR_GLOB = new Bun.Glob("*/") - for await (const item of UNEXPECTED_DIR_GLOB.scan({ - absolute: true, - followSymlinks: true, - dot: true, - cwd: dir, - onlyFiles: false, - })) { - const dirname = path.basename(item) - if (!ALLOWED_DIRS.has(dirname)) { - throw new InvalidError({ - path: dir, - message: `Unexpected directory "${dirname}" found in "${dir}". Only ${ALLOWED_DIRS.values().toArray().join(", ")} directories are allowed.`, - }) - } + const invalid = await Array.fromAsync( + INVALID_DIRS.scan({ + onlyFiles: false, + cwd: dir, + }), + ) + for (const item of invalid) { + throw new DirectoryError({ + path: dir, + dir: item, + suggestion: item.substring(0, item.length - 1), + }) } } + async function installDependencies(dir: string) { + await Bun.write(path.join(dir, "package.json"), "{}") + await Bun.write(path.join(dir, ".gitignore"), ["node_modules", "package.json", "bun.lock", ".gitignore"].join("\n")) + await BunProc.run( + ["add", "@opencode-ai/plugin@" + (Installation.isDev() ? "latest" : Installation.VERSION), "--exact"], + { + cwd: dir, + }, + ) + } + const COMMAND_GLOB = new Bun.Glob("command/**/*.md") async function loadCommand(dir: string) { const result: Record<string, Command> = {} @@ -680,10 +691,10 @@ export namespace Config { } const data = parsed.data if (data.plugin) { - for (let i = 0; i < data.plugin?.length; i++) { + for (let i = 0; i < data.plugin.length; i++) { const plugin = data.plugin[i] try { - data.plugin[i] = import.meta.resolve(plugin, configFilepath) + data.plugin[i] = import.meta.resolve!(plugin, configFilepath) } catch (err) {} } } @@ -700,6 +711,15 @@ export namespace Config { }), ) + export const DirectoryError = NamedError.create( + "ConfigDirectoryError", + z.object({ + path: z.string(), + dir: z.string(), + suggestion: z.string(), + }), + ) + export const InvalidError = NamedError.create( "ConfigInvalidError", z.object({ diff --git a/packages/opencode/src/file/ignore.ts b/packages/opencode/src/file/ignore.ts index 912f2159e..2e1d1428f 100644 --- a/packages/opencode/src/file/ignore.ts +++ b/packages/opencode/src/file/ignore.ts @@ -1,28 +1,30 @@ +import { sep } from "node:path" + export namespace FileIgnore { - const DEFAULT_PATTERNS = [ - // Dependencies - "**/node_modules/**", - "**/bower_components/**", - "**/.pnpm-store/**", - "**/vendor/**", - - // Build outputs - "**/dist/**", - "**/build/**", - "**/out/**", - "**/.next/**", - "**/target/**", // Rust - "**/bin/**", - "**/obj/**", // .NET - - // Version control - "**/.git/**", - "**/.svn/**", - "**/.hg/**", - - // IDE/Editor - "**/.vscode/**", - "**/.idea/**", + const FOLDERS = new Set([ + "node_modules", + "bower_components", + ".pnpm-store", + "vendor", + "dist", + "build", + "out", + ".next", + "target", + "bin", + "obj", + ".git", + ".svn", + ".hg", + ".vscode", + ".idea", + ".turbo", + ".output", + "desktop", + ".sst", + ]) + + const FILES = [ "**/*.swp", "**/*.swo", @@ -41,22 +43,31 @@ export namespace FileIgnore { "**/.nyc_output/**", ] - const GLOBS = DEFAULT_PATTERNS.map((p) => new Bun.Glob(p)) + const FILE_GLOBS = FILES.map((p) => new Bun.Glob(p)) + + export const PATTERNS = [...FILES, ...FOLDERS] export function match( filepath: string, - opts: { + opts?: { extra?: Bun.Glob[] whitelist?: Bun.Glob[] }, ) { - for (const glob of opts.whitelist || []) { + for (const glob of opts?.whitelist || []) { if (glob.match(filepath)) return false } - const extra = opts.extra || [] - for (const glob of [...GLOBS, ...extra]) { + + const parts = filepath.split(sep) + for (let i = 0; i < parts.length; i++) { + if (FOLDERS.has(parts[i])) return true + } + + const extra = opts?.extra || [] + for (const glob of [...FILE_GLOBS, ...extra]) { if (glob.match(filepath)) return true } + return false } } diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index 652cb7853..1bae71cfb 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -1,11 +1,13 @@ import z from "zod/v4" import { Bus } from "../bus" -import chokidar from "chokidar" import { Flag } from "../flag/flag" import { Instance } from "../project/instance" import { Log } from "../util/log" import { FileIgnore } from "./ignore" import { Config } from "../config/config" +// @ts-ignore +import { createWrapper } from "@parcel/watcher/wrapper" +import { lazy } from "@/util/lazy" export namespace FileWatcher { const log = Log.create({ service: "file.watcher" }) @@ -20,37 +22,48 @@ export namespace FileWatcher { ), } + const watcher = lazy(() => { + const binding = require( + `@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? "-glibc" : ""}`, + ) + return createWrapper(binding) as typeof import("@parcel/watcher") + }) + const state = Instance.state( async () => { if (Instance.project.vcs !== "git") return {} log.info("init") const cfg = await Config.get() - const ignore = (cfg.watcher?.ignore ?? []).map((v) => new Bun.Glob(v)) - const watcher = chokidar.watch(Instance.directory, { - ignoreInitial: true, - ignored: (filepath) => { - return FileIgnore.match(filepath, { - whitelist: [new Bun.Glob("**/.git/{index,logs/HEAD}")], - extra: ignore, - }) + const backend = (() => { + if (process.platform === "win32") return "windows" + if (process.platform === "darwin") return "fs-events" + if (process.platform === "linux") return "inotify" + })() + if (!backend) { + log.error("watcher backend not supported", { platform: process.platform }) + return {} + } + log.info("watcher backend", { platform: process.platform, backend }) + const sub = await watcher().subscribe( + Instance.directory, + (err, evts) => { + if (err) return + for (const evt of evts) { + log.info("event", evt) + if (evt.type === "create") Bus.publish(Event.Updated, { file: evt.path, event: "add" }) + if (evt.type === "update") Bus.publish(Event.Updated, { file: evt.path, event: "change" }) + if (evt.type === "delete") Bus.publish(Event.Updated, { file: evt.path, event: "unlink" }) + } + }, + { + ignore: [...FileIgnore.PATTERNS, ...(cfg.watcher?.ignore ?? [])], + backend, }, - }) - watcher.on("change", (file) => { - Bus.publish(Event.Updated, { file, event: "change" }) - }) - watcher.on("add", (file) => { - Bus.publish(Event.Updated, { file, event: "add" }) - }) - watcher.on("unlink", (file) => { - Bus.publish(Event.Updated, { file, event: "unlink" }) - }) - watcher.on("ready", () => { - log.info("ready") - }) - return { watcher } + ) + return { sub } }, async (state) => { - state.watcher?.close() + state.sub?.unsubscribe() }, ) diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 501279dd4..0437c4c69 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -12,6 +12,7 @@ export namespace Flag { // Experimental export const OPENCODE_EXPERIMENTAL_WATCHER = truthy("OPENCODE_EXPERIMENTAL_WATCHER") + export const OPENCODE_EXPERIMENTAL_NO_BOOTSTRAP = truthy("OPENCODE_EXPERIMENTAL_NO_BOOTSTRAP") function truthy(key: string) { const value = process.env[key]?.toLowerCase() diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index 66cc8eaa8..8a6589680 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -39,8 +39,8 @@ export namespace LSPClient { l.info("starting client") const connection = createMessageConnection( - new StreamMessageReader(input.server.process.stdout), - new StreamMessageWriter(input.server.process.stdin), + new StreamMessageReader(input.server.process.stdout as any), + new StreamMessageWriter(input.server.process.stdin as any), ) const diagnostics = new Map<string, Diagnostic[]>() diff --git a/packages/opencode/src/lsp/language.ts b/packages/opencode/src/lsp/language.ts index 2b6e0476c..8ab7f48dc 100644 --- a/packages/opencode/src/lsp/language.ts +++ b/packages/opencode/src/lsp/language.ts @@ -52,7 +52,8 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = { ".m": "objective-c", ".mm": "objective-cpp", ".pl": "perl", - ".pm": "perl6", + ".pm": "perl", + ".pm6": "perl6", ".php": "php", ".ps1": "powershell", ".psm1": "powershell", diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index c680c2896..17211da11 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -25,11 +25,11 @@ export namespace LSPServer { const files = Filesystem.up({ targets: patterns, start: path.dirname(file), - stop: Instance.worktree, + stop: Instance.directory, }) const first = await files.next() await files.return() - if (!first.value) return Instance.worktree + if (!first.value) return Instance.directory return path.dirname(first.value) } } @@ -44,7 +44,7 @@ export namespace LSPServer { export const Typescript: Info = { id: "typescript", - root: NearestRoot(["tsconfig.json", "package.json", "jsconfig.json"]), + root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"], async spawn(root) { const tsserver = await Bun.resolve("typescript/lib/tsserver.js", Instance.directory).catch(() => {}) @@ -70,20 +70,7 @@ export namespace LSPServer { export const Vue: Info = { id: "vue", extensions: [".vue"], - root: NearestRoot([ - "tsconfig.json", - "jsconfig.json", - "package.json", - "pnpm-lock.yaml", - "yarn.lock", - "bun.lockb", - "bun.lock", - "vite.config.ts", - "vite.config.js", - "nuxt.config.ts", - "nuxt.config.js", - "vue.config.js", - ]), + root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), async spawn(root) { let binary = Bun.which("vue-language-server") const args: string[] = [] @@ -131,20 +118,7 @@ export namespace LSPServer { export const ESLint: Info = { id: "eslint", - root: NearestRoot([ - "eslint.config.js", - "eslint.config.mjs", - "eslint.config.cjs", - "eslint.config.ts", - "eslint.config.mts", - "eslint.config.cts", - ".eslintrc.js", - ".eslintrc.cjs", - ".eslintrc.yaml", - ".eslintrc.yml", - ".eslintrc.json", - "package.json", - ]), + root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"], async spawn(root) { const eslint = await Bun.resolve("eslint", Instance.directory).catch(() => {}) @@ -659,19 +633,7 @@ export namespace LSPServer { export const Svelte: Info = { id: "svelte", extensions: [".svelte"], - root: NearestRoot([ - "tsconfig.json", - "jsconfig.json", - "package.json", - "pnpm-lock.yaml", - "yarn.lock", - "bun.lockb", - "bun.lock", - "vite.config.ts", - "vite.config.js", - "svelte.config.ts", - "svelte.config.js", - ]), + root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), async spawn(root) { let binary = Bun.which("svelteserver") const args: string[] = [] diff --git a/packages/opencode/src/project/bootstrap.ts b/packages/opencode/src/project/bootstrap.ts index a3037528f..b636cb3ea 100644 --- a/packages/opencode/src/project/bootstrap.ts +++ b/packages/opencode/src/project/bootstrap.ts @@ -5,8 +5,10 @@ import { LSP } from "../lsp" import { Snapshot } from "../snapshot" import { FileWatcher } from "../file/watcher" import { File } from "../file" +import { Flag } from "../flag/flag" export async function InstanceBootstrap() { + if (Flag.OPENCODE_EXPERIMENTAL_NO_BOOTSTRAP) return await Plugin.init() Share.init() Format.init() diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index 514203e91..97310dd19 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -28,6 +28,12 @@ export namespace ModelsDev { context: z.number(), output: z.number(), }), + modalities: z + .object({ + input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])), + output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])), + }) + .optional(), experimental: z.boolean().optional(), options: z.record(z.string(), z.any()), provider: z.object({ npm: z.string() }).optional(), diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index c18bc4898..e0fe4be23 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -279,6 +279,11 @@ export namespace Provider { context: 0, output: 0, }, + modalities: model.modalities ?? + existing?.modalities ?? { + input: ["text"], + output: ["text"], + }, provider: model.provider ?? existing?.provider, } parsed.models[modelID] = parsedModel diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 7704a6155..8dc059ca1 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -17,71 +17,6 @@ export namespace MessageV2 { }), ) - export const ToolStatePending = z - .object({ - status: z.literal("pending"), - }) - .meta({ - ref: "ToolStatePending", - }) - - export type ToolStatePending = z.infer<typeof ToolStatePending> - - export const ToolStateRunning = z - .object({ - status: z.literal("running"), - input: z.any(), - title: z.string().optional(), - metadata: z.record(z.string(), z.any()).optional(), - time: z.object({ - start: z.number(), - }), - }) - .meta({ - ref: "ToolStateRunning", - }) - export type ToolStateRunning = z.infer<typeof ToolStateRunning> - - export const ToolStateCompleted = z - .object({ - status: z.literal("completed"), - input: z.record(z.string(), z.any()), - output: z.string(), - title: z.string(), - metadata: z.record(z.string(), z.any()), - time: z.object({ - start: z.number(), - end: z.number(), - compacted: z.number().optional(), - }), - }) - .meta({ - ref: "ToolStateCompleted", - }) - export type ToolStateCompleted = z.infer<typeof ToolStateCompleted> - - export const ToolStateError = z - .object({ - status: z.literal("error"), - input: z.record(z.string(), z.any()), - error: z.string(), - metadata: z.record(z.string(), z.any()).optional(), - time: z.object({ - start: z.number(), - end: z.number(), - }), - }) - .meta({ - ref: "ToolStateError", - }) - export type ToolStateError = z.infer<typeof ToolStateError> - - export const ToolState = z - .discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]) - .meta({ - ref: "ToolState", - }) - const PartBase = z.object({ id: z.string(), sessionID: z.string(), @@ -134,17 +69,6 @@ export namespace MessageV2 { }) export type ReasoningPart = z.infer<typeof ReasoningPart> - export const ToolPart = PartBase.extend({ - type: z.literal("tool"), - callID: z.string(), - tool: z.string(), - state: ToolState, - metadata: z.record(z.string(), z.any()).optional(), - }).meta({ - ref: "ToolPart", - }) - export type ToolPart = z.infer<typeof ToolPart> - const FilePartSourceBase = z.object({ text: z .object({ @@ -228,6 +152,83 @@ export namespace MessageV2 { }) export type StepFinishPart = z.infer<typeof StepFinishPart> + export const ToolStatePending = z + .object({ + status: z.literal("pending"), + }) + .meta({ + ref: "ToolStatePending", + }) + + export type ToolStatePending = z.infer<typeof ToolStatePending> + + export const ToolStateRunning = z + .object({ + status: z.literal("running"), + input: z.any(), + title: z.string().optional(), + metadata: z.record(z.string(), z.any()).optional(), + time: z.object({ + start: z.number(), + }), + }) + .meta({ + ref: "ToolStateRunning", + }) + export type ToolStateRunning = z.infer<typeof ToolStateRunning> + + export const ToolStateCompleted = z + .object({ + status: z.literal("completed"), + input: z.record(z.string(), z.any()), + output: z.string(), + title: z.string(), + metadata: z.record(z.string(), z.any()), + time: z.object({ + start: z.number(), + end: z.number(), + compacted: z.number().optional(), + }), + attachments: FilePart.array().optional(), + }) + .meta({ + ref: "ToolStateCompleted", + }) + export type ToolStateCompleted = z.infer<typeof ToolStateCompleted> + + export const ToolStateError = z + .object({ + status: z.literal("error"), + input: z.record(z.string(), z.any()), + error: z.string(), + metadata: z.record(z.string(), z.any()).optional(), + time: z.object({ + start: z.number(), + end: z.number(), + }), + }) + .meta({ + ref: "ToolStateError", + }) + export type ToolStateError = z.infer<typeof ToolStateError> + + export const ToolState = z + .discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]) + .meta({ + ref: "ToolState", + }) + + export const ToolPart = PartBase.extend({ + type: z.literal("tool"), + callID: z.string(), + tool: z.string(), + state: ToolState, + metadata: z.record(z.string(), z.any()).optional(), + }).meta({ + ref: "ToolPart", + }) + export type ToolPart = z.infer<typeof ToolPart> + const Base = z.object({ id: z.string(), sessionID: z.string(), @@ -531,7 +532,25 @@ export namespace MessageV2 { }, ] if (part.type === "tool") { - if (part.state.status === "completed") + if (part.state.status === "completed") { + if (part.state.attachments?.length) { + result.push({ + id: Identifier.ascending("message"), + role: "user", + parts: [ + { + type: "text", + text: `Tool ${part.tool} returned an attachment:`, + }, + ...part.state.attachments.map((attachment) => ({ + type: "file" as const, + url: attachment.url, + mediaType: attachment.mime, + filename: attachment.filename, + })), + ], + }) + } return [ { type: ("tool-" + part.tool) as `tool-${string}`, @@ -542,6 +561,7 @@ export namespace MessageV2 { callProviderMetadata: part.metadata, }, ] + } if (part.state.status === "error") return [ { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index b65309d9e..0ccb208c6 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -457,6 +457,10 @@ export namespace SessionPrompt { abort: options.abortSignal!, messageID: input.processor.message.id, callID: options.toolCallId, + extra: { + modelID: input.modelID, + providerID: input.providerID, + }, agent: input.agent.name, metadata: async (val) => { const match = input.processor.partFromToolCall(options.toolCallId) @@ -989,6 +993,7 @@ export namespace SessionPrompt { start: match.state.time.start, end: Date.now(), }, + attachments: value.output.attachments, }, }) delete toolcalls[value.toolCallId] diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index 2ed3accbd..5e8cecaf2 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -7,6 +7,8 @@ import { FileTime } from "../file/time" import DESCRIPTION from "./read.txt" import { Filesystem } from "../util/filesystem" import { Instance } from "../project/instance" +import { Provider } from "../provider/provider" +import { Identifier } from "../id/id" const DEFAULT_READ_LIMIT = 2000 const MAX_LINE_LENGTH = 2000 @@ -23,6 +25,8 @@ export const ReadTool = Tool.define("read", { if (!path.isAbsolute(filepath)) { filepath = path.join(process.cwd(), filepath) } + const title = path.relative(Instance.worktree, filepath) + if (!ctx.extra?.["bypassCwdCheck"] && !Filesystem.contains(Instance.directory, filepath)) { throw new Error(`File ${filepath} is not in the current working directory`) } @@ -48,12 +52,45 @@ export const ReadTool = Tool.define("read", { throw new Error(`File not found: ${filepath}`) } - const limit = params.limit ?? DEFAULT_READ_LIMIT - const offset = params.offset || 0 const isImage = isImageFile(filepath) - if (isImage) throw new Error(`This is an image file of type: ${isImage}\nUse a different tool to process images`) + const supportsImages = await (async () => { + if (!ctx.extra?.["providerID"] || !ctx.extra?.["modelID"]) return false + const providerID = ctx.extra["providerID"] as string + const modelID = ctx.extra["modelID"] as string + const model = await Provider.getModel(providerID, modelID).catch(() => undefined) + if (!model) return false + return model.info.modalities?.input?.includes("image") ?? false + })() + if (isImage) { + if (!supportsImages) { + throw new Error(`Failed to read image: ${filepath}, model may not be able to read images`) + } + const mime = file.type + const msg = "Image read successfully" + return { + title, + output: msg, + metadata: { + preview: msg, + }, + attachments: [ + { + id: Identifier.ascending("part"), + sessionID: ctx.sessionID, + messageID: ctx.messageID, + type: "file", + mime, + url: `data:${mime};base64,${Buffer.from(await file.bytes()).toString("base64")}`, + }, + ], + } + } + const isBinary = await isBinaryFile(filepath, file) if (isBinary) throw new Error(`Cannot read binary file: ${filepath}`) + + const limit = params.limit ?? DEFAULT_READ_LIMIT + const offset = params.offset || 0 const lines = await file.text().then((text) => text.split("\n")) const raw = lines.slice(offset, offset + limit).map((line) => { return line.length > MAX_LINE_LENGTH ? line.substring(0, MAX_LINE_LENGTH) + "..." : line @@ -76,7 +113,7 @@ export const ReadTool = Tool.define("read", { FileTime.read(ctx.sessionID, filepath) return { - title: path.relative(Instance.worktree, filepath), + title, output, metadata: { preview, diff --git a/packages/opencode/src/tool/read.txt b/packages/opencode/src/tool/read.txt index 3904c0939..b5bffee26 100644 --- a/packages/opencode/src/tool/read.txt +++ b/packages/opencode/src/tool/read.txt @@ -7,6 +7,6 @@ Usage: - You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters - Any lines longer than 2000 characters will be truncated - Results are returned using cat -n format, with line numbers starting at 1 -- This tool cannot read binary files, including images -- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful. +- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful. - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents. +- You can read image files using this tool. diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts index a372a69d7..2fc72274d 100644 --- a/packages/opencode/src/tool/tool.ts +++ b/packages/opencode/src/tool/tool.ts @@ -1,9 +1,11 @@ import z from "zod/v4" +import type { MessageV2 } from "../session/message-v2" export namespace Tool { interface Metadata { [key: string]: any } + export type Context<M extends Metadata = Metadata> = { sessionID: string messageID: string @@ -25,6 +27,7 @@ export namespace Tool { title: string metadata: M output: string + attachments?: MessageV2.FilePart[] }> }> } diff --git a/packages/opencode/src/util/context.ts b/packages/opencode/src/util/context.ts index 1e5db36a7..b56329d84 100644 --- a/packages/opencode/src/util/context.ts +++ b/packages/opencode/src/util/context.ts @@ -18,7 +18,7 @@ export namespace Context { return result }, provide<R>(value: T, fn: () => R) { - return storage.run<R>(value, fn) + return storage.run(value, fn) }, } } diff --git a/packages/opencode/test/file/ignore.test.ts b/packages/opencode/test/file/ignore.test.ts new file mode 100644 index 000000000..6387ff63e --- /dev/null +++ b/packages/opencode/test/file/ignore.test.ts @@ -0,0 +1,10 @@ +import { test, expect } from "bun:test" +import { FileIgnore } from "../../src/file/ignore" + +test("match nested and non-nested", () => { + expect(FileIgnore.match("node_modules/index.js")).toBe(true) + expect(FileIgnore.match("node_modules")).toBe(true) + expect(FileIgnore.match("node_modules/")).toBe(true) + expect(FileIgnore.match("node_modules/bar")).toBe(true) + expect(FileIgnore.match("node_modules/bar/")).toBe(true) +}) diff --git a/packages/opencode/test/snapshot/snapshot.test.ts b/packages/opencode/test/snapshot/snapshot.test.ts index 1398162e3..0ffed351f 100644 --- a/packages/opencode/test/snapshot/snapshot.test.ts +++ b/packages/opencode/test/snapshot/snapshot.test.ts @@ -123,7 +123,7 @@ test("binary file handling", async () => { const before = await Snapshot.track() expect(before).toBeTruthy() - await Bun.write(`${tmp.path}/image.png`, Buffer.from([0x89, 0x50, 0x4e, 0x47])) + await Bun.write(`${tmp.path}/image.png`, new Uint8Array([0x89, 0x50, 0x4e, 0x47])) const patch = await Snapshot.patch(before!) expect(patch.files).toContain(`${tmp.path}/image.png`) diff --git a/packages/opencode/tsconfig.json b/packages/opencode/tsconfig.json index 167d7936c..478672ce9 100644 --- a/packages/opencode/tsconfig.json +++ b/packages/opencode/tsconfig.json @@ -5,6 +5,7 @@ "jsx": "preserve", "jsxImportSource": "@opentui/solid", "lib": ["ESNext", "DOM", "DOM.Iterable"], + "types": [], "customConditions": ["browser"], "baseUrl": ".", "paths": { diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 36deca0cf..2b49cd010 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": "0.14.6", + "version": "0.14.7", "type": "module", "scripts": { "typecheck": "tsc --noEmit", @@ -20,6 +20,7 @@ }, "devDependencies": { "@tsconfig/node22": "catalog:", + "@types/node": "24.7.1", "typescript": "catalog:" } }
\ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 56390dd57..3f6073e34 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": "0.14.6", + "version": "0.14.7", "type": "module", "scripts": { "typecheck": "tsc --noEmit", @@ -16,13 +16,12 @@ "dist" ], "devDependencies": { - "typescript": "catalog:", - "@hey-api/openapi-ts": "0.80.1", - "@tsconfig/node22": "catalog:" - }, - "dependencies": { - "@hey-api/openapi-ts": "0.81.0" + "@hey-api/openapi-ts": "0.81.0", + "@tsconfig/node22": "catalog:", + "@types/node": "24.7.1", + "typescript": "catalog:" }, + "dependencies": {}, "publishConfig": { "directory": "dist" } diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index cc94c1f1f..706fff125 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -413,6 +413,10 @@ export type Config = { context: number output: number } + modalities?: { + input: Array<"text" | "audio" | "image" | "video" | "pdf"> + output: Array<"text" | "audio" | "image" | "video" | "pdf"> + } experimental?: boolean options?: { [key: string]: unknown @@ -746,6 +750,7 @@ export type ToolStateCompleted = { end: number compacted?: number } + attachments?: Array<FilePart> } export type ToolStateError = { @@ -904,6 +909,10 @@ export type Model = { context: number output: number } + modalities?: { + input: Array<"text" | "audio" | "image" | "video" | "pdf"> + output: Array<"text" | "audio" | "image" | "video" | "pdf"> + } experimental?: boolean options: { [key: string]: unknown diff --git a/packages/web/astro.config.mjs b/packages/web/astro.config.mjs index fb7bd75b5..3bcd98cb7 100644 --- a/packages/web/astro.config.mjs +++ b/packages/web/astro.config.mjs @@ -74,6 +74,7 @@ export default defineConfig({ { label: "Configure", items: [ + "tools", "rules", "agents", "models", diff --git a/packages/web/package.json b/packages/web/package.json index b01a51e2a..b3390c169 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "0.14.6", + "version": "0.14.7", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", @@ -31,7 +31,7 @@ "sharp": "0.32.5", "shiki": "3.4.2", "solid-js": "catalog:", - "toolbeam-docs-theme": "0.4.7" + "toolbeam-docs-theme": "0.4.8" }, "devDependencies": { "opencode": "workspace:*", diff --git a/packages/web/src/content/docs/agents.mdx b/packages/web/src/content/docs/agents.mdx index 7016d6576..e15ba6cb1 100644 --- a/packages/web/src/content/docs/agents.mdx +++ b/packages/web/src/content/docs/agents.mdx @@ -303,27 +303,33 @@ Use the `model` config to override the default model for this agent. Useful for Control which tools are available in this agent with the `tools` config. You can enable or disable specific tools by setting them to `true` or `false`. -```json title="opencode.json" +```json title="opencode.json" {3-6,9-12} { + "$schema": "https://opencode.ai/config.json", + "tools": { + "write": true, + "bash": true + }, "agent": { - "readonly": { + "plan": { "tools": { "write": false, - "edit": false, - "bash": false, - "read": true, - "grep": true, - "glob": true + "bash": false } } } } ``` +:::note +The agent-specific config overrides the global config. +::: + You can also use wildcards to control multiple tools at once. For example, to disable all tools from an MCP server: ```json title="opencode.json" { + "$schema": "https://opencode.ai/config.json", "agent": { "readonly": { "tools": { @@ -336,27 +342,7 @@ You can also use wildcards to control multiple tools at once. For example, to di } ``` -If no tools are specified, all tools are enabled by default. - ---- - -#### Available tools - -Here are all the tools can be controlled through the agent config. - -| Tool | Description | -| ----------- | ----------------------- | -| `bash` | Execute shell commands | -| `edit` | Modify existing files | -| `write` | Create new files | -| `read` | Read file contents | -| `grep` | Search file contents | -| `glob` | Find files by pattern | -| `list` | List directory contents | -| `patch` | Apply patches to files | -| `todowrite` | Manage todo lists | -| `todoread` | Read todo lists | -| `webfetch` | Fetch web content | +[Learn more about tools](/docs/tools). --- diff --git a/packages/web/src/content/docs/config.mdx b/packages/web/src/content/docs/config.mdx index d996cb94b..f3b2a05a0 100644 --- a/packages/web/src/content/docs/config.mdx +++ b/packages/web/src/content/docs/config.mdx @@ -86,6 +86,24 @@ You can configure TUI-specific settings through the `tui` option. --- +### Tools + +You can manage the tools an LLM can use through the `tools` option. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "write": false, + "bash": false + } +} +``` + +[Learn more about tools here](/docs/tools). + +--- + ### Models You can configure the providers and models you want to use in your OpenCode config through the `provider`, `model` and `small_model` options. diff --git a/packages/web/src/content/docs/custom-tools.mdx b/packages/web/src/content/docs/custom-tools.mdx index d982475ef..3f4cf06bc 100644 --- a/packages/web/src/content/docs/custom-tools.mdx +++ b/packages/web/src/content/docs/custom-tools.mdx @@ -3,7 +3,7 @@ title: Custom Tools description: Create tools the LLM can call in opencode. --- -Custom tools are functions you create that the LLM can call during conversations. They work alongside opencode's built-in tools like `read`, `write`, and `bash`. +Custom tools are functions you create that the LLM can call during conversations. They work alongside opencode's [built-in tools](/docs/tools) like `read`, `write`, and `bash`. --- diff --git a/packages/web/src/content/docs/mcp-servers.mdx b/packages/web/src/content/docs/mcp-servers.mdx index 0ceeb47a3..535e22839 100644 --- a/packages/web/src/content/docs/mcp-servers.mdx +++ b/packages/web/src/content/docs/mcp-servers.mdx @@ -3,10 +3,10 @@ title: MCP servers description: Add local and remote MCP tools. --- -You can add external tools to opencode using the _Model Context Protocol_, or MCP. opencode supports both: +You can add external tools to OpenCode using the _Model Context Protocol_, or MCP. OpenCode supports both: - Local servers -- And remote servers +- Remote servers Once added, MCP tools are automatically available to the LLM alongside built-in tools. @@ -14,15 +14,22 @@ Once added, MCP tools are automatically available to the LLM alongside built-in ## Configure -You can define MCP servers in your opencode config under `mcp`. +You can define MCP servers in your OpenCode config under `mcp`. --- ### Local -Add local MCP servers using `"type": "local"` within the MCP object. Multiple MCP servers can be added. The key string for each server can be any arbitrary name. +Add local MCP servers using `"type": "local"` within the MCP object. Multiple MCP servers can be added. -```json title="opencode.json" +:::tip +MCP servers add to your context, so you want to be careful with which +ones you enable. +::: + +The key string for each server can be any arbitrary name. + +```json title="opencode.json" {15} { "$schema": "https://opencode.ai/config.json", "mcp": { @@ -95,16 +102,70 @@ Local and remote servers can be used together within the same `mcp` config objec --- -## Per agent +## Manage + +Your MCPs are available as tools in OpenCode, alongside built-in tools. So you +can manage them through the OpenCode config like any other tool. + +--- + +### Global + +This means that you can enable or disable them globally. + +```json title="opencode.json" {14} +{ + "$schema": "https://opencode.ai/config.json", + "mcp": { + "my-mcp-foo": { + "type": "local", + "command": ["bun", "x", "my-mcp-command-foo"] + }, + "my-mcp-bar": { + "type": "local", + "command": ["bun", "x", "my-mcp-command-bar"] + } + }, + "tools": { + "my-mcp-foo": false + } +} +``` + +We can also use a glob pattern to disable all matching MCPs. + +```json title="opencode.json" {14} +{ + "$schema": "https://opencode.ai/config.json", + "mcp": { + "my-mcp-foo": { + "type": "local", + "command": ["bun", "x", "my-mcp-command-foo"] + }, + "my-mcp-bar": { + "type": "local", + "command": ["bun", "x", "my-mcp-command-bar"] + } + }, + "tools": { + "my-mcp*": false + } +} +``` + +Here we are using the glob pattern `my-mcp*` to disable all MCPs. + +--- + +### Per agent If you have a large number of MCP servers you may want to only enable them per agent and disable them globally. To do this: -1. Configure the MCP server. -2. Disable it as a tool globally. -3. In your [agent config](/docs/agents#tools) enable the MCP server as a tool. +1. Disable it as a tool globally. +2. In your [agent config](/docs/agents#tools) enable the MCP server as a tool. -```json title="opencode.json" {11, 14-17} +```json title="opencode.json" {11, 14-18} { "$schema": "https://opencode.ai/config.json", "mcp": { @@ -126,3 +187,13 @@ agent and disable them globally. To do this: } } ``` + +--- + +#### Glob patterns + +The glob pattern uses simple regex globbing patterns. + +- `*` matches zero or more of any character +- `?` matches exactly one character +- All other characters match literally diff --git a/packages/web/src/content/docs/plugins.mdx b/packages/web/src/content/docs/plugins.mdx index bfcf1ed87..fe1ae9bfd 100644 --- a/packages/web/src/content/docs/plugins.mdx +++ b/packages/web/src/content/docs/plugins.mdx @@ -111,7 +111,7 @@ export const EnvProtection = async ({ project, client, $, directory, worktree }) Plugins can also add custom tools to opencode: ```ts title=".opencode/plugin/custom-tools.ts" -import type { Plugin, tool } from "@opencode-ai/plugin" +import { type Plugin, tool } from "@opencode-ai/plugin" export const CustomToolsPlugin: Plugin = async (ctx) => { return { diff --git a/packages/web/src/content/docs/tools.mdx b/packages/web/src/content/docs/tools.mdx new file mode 100644 index 000000000..11761d4c8 --- /dev/null +++ b/packages/web/src/content/docs/tools.mdx @@ -0,0 +1,316 @@ +--- +title: Tools +description: Manage the tools an LLM can use. +--- + +Tools allow the LLM to perform actions in your codebase. OpenCode comes with a set of built-in tools, but you can extend it with [custom tools](/docs/custom-tools) or [MCP servers](/docs/mcp-servers). + +By default, all tools are **enabled** and don't need permission to run. But you can configure this and control the [permissions](/docs/permissions) through your config. + +--- + +## Configure + +You can configure tools globally or per agent. Agent-specific configs override global settings. + +By default, all tools are set to `true`. To disable a tool, set it to `false`. + +--- + +### Global + +Disable or enable tools globally using the `tools` option. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "write": false, + "bash": false, + "webfetch": true + } +} +``` + +You can also use wildcards to control multiple tools at once. For example, to disable all tools from an MCP server: + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "mymcp_*": false + } +} +``` + +--- + +### Per agent + +Override global tool settings for specific agents using the `tools` config in the agent definition. + +```json title="opencode.json" {3-6,9-12} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "write": true, + "bash": true + }, + "agent": { + "plan": { + "tools": { + "write": false, + "bash": false + } + } + } +} +``` + +For example, here the `plan` agent overrides the global config to disable `write` and `bash` tools. + +You can also configure tools for agents in Markdown. + +```markdown title="~/.config/opencode/agent/readonly.md" +--- +description: Read-only analysis agent +mode: subagent +tools: + write: false + edit: false + bash: false +--- + +Analyze code without making any modifications. +``` + +[Learn more](/docs/agents#tools) about configuring tools per agent. + +--- + +## Built-in + +Here are all the built-in tools available in OpenCode. + +--- + +### bash + +Execute shell commands in your project environment. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "bash": true + } +} +``` + +This tool allows the LLM to run terminal commands like `npm install`, `git status`, or any other shell command. + +--- + +### edit + +Modify existing files using exact string replacements. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "edit": true + } +} +``` + +This tool performs precise edits to files by replacing exact text matches. It's the primary way the LLM modifies code. + +--- + +### write + +Create new files or overwrite existing ones. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "write": true + } +} +``` + +Use this to allow the LLM to create new files. It will overwrite existing files if they already exist. + +--- + +### read + +Read file contents from your codebase. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "read": true + } +} +``` + +This tool reads files and returns their contents. It supports reading specific line ranges for large files. + +--- + +### grep + +Search file contents using regular expressions. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "grep": true + } +} +``` + +Fast content search across your codebase. Supports full regex syntax and file pattern filtering. + +--- + +### glob + +Find files by pattern matching. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "glob": true + } +} +``` + +Search for files using glob patterns like `**/*.js` or `src/**/*.ts`. Returns matching file paths sorted by modification time. + +--- + +### list + +List files and directories in a given path. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "list": true + } +} +``` + +This tool lists directory contents. It accepts glob patterns to filter results. + +--- + +### patch + +Apply patches to files. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "patch": true + } +} +``` + +This tool applies patch files to your codebase. Useful for applying diffs and patches from various sources. + +--- + +### todowrite + +Manage todo lists during coding sessions. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "todowrite": true + } +} +``` + +Creates and updates task lists to track progress during complex operations. The LLM uses this to organize multi-step tasks. + +--- + +### todoread + +Read existing todo lists. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "todoread": true + } +} +``` + +Reads the current todo list state. Used by the LLM to track what tasks are pending or completed. + +--- + +### webfetch + +Fetch web content. + +```json title="opencode.json" {4} +{ + "$schema": "https://opencode.ai/config.json", + "tools": { + "webfetch": true + } +} +``` + +Allows the LLM to fetch and read web pages. Useful for looking up documentation or researching online resources. + +--- + +## Custom tools + +Custom tools let you define your own functions that the LLM can call. These are defined in your config file and can execute arbitrary code. + +[Learn more](/docs/custom-tools) about creating custom tools. + +--- + +## MCP servers + +MCP (Model Context Protocol) servers allow you to integrate external tools and services. This includes database access, API integrations, and third-party services. + +[Learn more](/docs/mcp-servers) about configuring MCP servers. + +--- + +## Internals + +Internally, tools like `grep`, `glob`, and `list` use [ripgrep](https://github.com/BurntSushi/ripgrep) under the hood. By default, ripgrep respects `.gitignore` patterns, which means files and directories listed in your `.gitignore` will be excluded from searches and listings. + +--- + +### Ignore patterns + +To include files that would normally be ignored, create a `.ignore` file in your project root. This file can explicitly allow certain paths. + +```text title=".ignore" +!node_modules/ +!dist/ +!build/ +``` + +For example, this `.ignore` file allows ripgrep to search within `node_modules/`, `dist/`, and `build/` directories even if they're listed in `.gitignore`. diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 6bbe34a84..f1c2b3338 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -66,6 +66,7 @@ You can also access our models through the following API endpoints. | ---------------- | ---------------- | --------------------------------------------- | --------------------------- | | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | diff --git a/script/publish.ts b/script/publish.ts index a4f2ba663..05d6df222 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -2,8 +2,8 @@ import { $ } from "bun" import { createOpencode } from "@opencode-ai/sdk" -if (process.versions.bun !== "1.2.21") { - throw new Error("This script requires [email protected]") +if (process.versions.bun !== "1.3.0") { + throw new Error("This script requires [email protected]") } const notes = [] as string[] diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 0f7e8d238..e9e71e24d 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": "0.14.6", + "version": "0.14.7", "publisher": "sst-dev", "repository": { "type": "git", |
