Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d9319a20d | ||
|
|
3dc5a66de0 | ||
|
|
09446605ec | ||
|
|
1f9e8cc4a5 | ||
|
|
09c4b71632 | ||
|
|
c9bffc0f46 |
@@ -39,15 +39,6 @@ jobs:
|
||||
with:
|
||||
bun-version: 1.2.19
|
||||
|
||||
- name: Cache ~/.bun
|
||||
id: cache-bun
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.bun
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Install makepkg
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -62,11 +53,9 @@ jobs:
|
||||
git config --global user.email "opencode@sst.dev"
|
||||
git config --global user.name "opencode"
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
bun install
|
||||
OPENCODE_VERSION=${{ inputs.version }} ./script/publish.ts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Typecheck
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [dev]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: 1.2.19
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Run typecheck
|
||||
run: bun typecheck
|
||||
+1
-1
@@ -5,4 +5,4 @@ node_modules
|
||||
.idea
|
||||
.vscode
|
||||
openapi.json
|
||||
playground
|
||||
scratch
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Plugin } from "./index"
|
||||
|
||||
export const ExamplePlugin: Plugin = async ({ app, client, $ }) => {
|
||||
return {
|
||||
permission: {},
|
||||
async "chat.params"(input, output) {
|
||||
output.topP = 1
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -36,5 +36,3 @@
|
||||
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
|
||||
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
|
||||
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
|
||||
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
|
||||
| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) |
|
||||
|
||||
@@ -10,27 +10,22 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode/function",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "2.0.0",
|
||||
"@ai-sdk/openai": "2.0.2",
|
||||
"@ai-sdk/openai-compatible": "1.0.1",
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"ai": "catalog:",
|
||||
"hono": "catalog:",
|
||||
"jose": "6.0.11",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "4.20250522.0",
|
||||
"@types/node": "catalog:",
|
||||
"openai": "5.11.0",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -44,7 +39,6 @@
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@openauthjs/openauth": "0.4.3",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@zip.js/zip.js": "2.7.62",
|
||||
"ai": "catalog:",
|
||||
@@ -83,19 +77,17 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "0.3.129",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -104,7 +96,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode/web",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "^12.5.4",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -139,9 +131,6 @@
|
||||
"sharp",
|
||||
"esbuild",
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"marked-shiki@1.2.0": "patches/marked-shiki@1.2.0.patch",
|
||||
},
|
||||
"catalog": {
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"@types/node": "22.13.9",
|
||||
@@ -164,17 +153,13 @@
|
||||
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@2.2.10", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icLGO7Q0NinnHIPgT+y1QjHVwH4HwV+brWbvM+FfCG2Afpa89PyKa3Ret91kGjZpBgM/xnj1B7K5eM+rRlsXQA=="],
|
||||
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-uyyaO4KhxoIKZztREqLPh+6/K3ZJx/rp72JKoUEL9/kC+vfQTThUfPnY/bUryUpcnawx8IY/tSoYNOi/8PCv7w=="],
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@1.2.12", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ=="],
|
||||
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.0-beta.19", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@ai-sdk/provider-utils": "3.0.0-beta.10" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-felWPMuECZRGx8xnmvH5dW3jywKTkGnw/tXN8szphGzEDr/BfxywuXijfPBG2WBUS6frPXsvSLDRdCm5W38PXA=="],
|
||||
|
||||
"@ai-sdk/openai": ["@ai-sdk/openai@2.0.2", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-D4zYz2uR90aooKQvX1XnS00Z7PkbrcY+snUvPfm5bCabTG7bzLrVtD56nJ5bSaZG8lmuOMfXpyiEEArYLyWPpw=="],
|
||||
"@ai-sdk/provider": ["@ai-sdk/provider@2.0.0-beta.2", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-vqhtZA7R24q1XnmfmIb1fZSmHMIaJH1BVQ+0kFnNJgqWsc+V8i+yfetZ37gUc4fXATFmBuS/6O7+RPoHsZ2Fqg=="],
|
||||
|
||||
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.1", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-luHVcU+yKzwv3ekKgbP3v+elUVxb2Rt+8c6w9qi7g2NYG2/pEL21oIrnaEnc6UtTZLLZX9EFBcpq2N1FQKDIMw=="],
|
||||
|
||||
"@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="],
|
||||
|
||||
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw=="],
|
||||
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0-beta.10", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-e6WSsgM01au04/1L/v5daXHn00eKjPBQXl3jq3BfvQbQ1jo8Rls2pvrdkyVc25jBW4TV4Zm+tw+v6NAh5NPXMA=="],
|
||||
|
||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||
|
||||
@@ -1378,8 +1363,6 @@
|
||||
|
||||
"open": ["open@10.1.2", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw=="],
|
||||
|
||||
"openai": ["openai@5.11.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-+AuTc5pVjlnTuA9zvn8rA/k+1RluPIx9AD4eDcnutv6JNwHHZxIhkFy+tmMKCvmMFDQzfA/r1ujvPWB19DQkYg=="],
|
||||
|
||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||
|
||||
"opencode": ["opencode@workspace:packages/opencode"],
|
||||
@@ -1854,9 +1837,9 @@
|
||||
|
||||
"@ai-sdk/amazon-bedrock/aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
||||
|
||||
"@ai-sdk/gateway/@ai-sdk/provider": ["@ai-sdk/provider@2.0.0-beta.2", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-vqhtZA7R24q1XnmfmIb1fZSmHMIaJH1BVQ+0kFnNJgqWsc+V8i+yfetZ37gUc4fXATFmBuS/6O7+RPoHsZ2Fqg=="],
|
||||
"@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="],
|
||||
|
||||
"@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0-beta.10", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-e6WSsgM01au04/1L/v5daXHn00eKjPBQXl3jq3BfvQbQ1jo8Rls2pvrdkyVc25jBW4TV4Zm+tw+v6NAh5NPXMA=="],
|
||||
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="],
|
||||
|
||||
"@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="],
|
||||
|
||||
@@ -1888,10 +1871,6 @@
|
||||
|
||||
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"ai/@ai-sdk/provider": ["@ai-sdk/provider@2.0.0-beta.2", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-vqhtZA7R24q1XnmfmIb1fZSmHMIaJH1BVQ+0kFnNJgqWsc+V8i+yfetZ37gUc4fXATFmBuS/6O7+RPoHsZ2Fqg=="],
|
||||
|
||||
"ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0-beta.10", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-e6WSsgM01au04/1L/v5daXHn00eKjPBQXl3jq3BfvQbQ1jo8Rls2pvrdkyVc25jBW4TV4Zm+tw+v6NAh5NPXMA=="],
|
||||
|
||||
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
@@ -1932,8 +1911,6 @@
|
||||
|
||||
"nypm/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@1.2.12", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ=="],
|
||||
|
||||
"opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="],
|
||||
|
||||
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
|
||||
@@ -2020,10 +1997,6 @@
|
||||
|
||||
"gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
|
||||
|
||||
"opencode/@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="],
|
||||
|
||||
"opencode/@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="],
|
||||
|
||||
"opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="],
|
||||
|
||||
"opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
|
||||
|
||||
@@ -46,15 +46,3 @@ new sst.cloudflare.x.Astro("Web", {
|
||||
VITE_API_URL: api.url,
|
||||
},
|
||||
})
|
||||
|
||||
const OPENCODE_API_KEY = new sst.Secret("OPENCODE_API_KEY")
|
||||
const ANTHROPIC_API_KEY = new sst.Secret("ANTHROPIC_API_KEY")
|
||||
const OPENAI_API_KEY = new sst.Secret("OPENAI_API_KEY")
|
||||
const ZHIPU_API_KEY = new sst.Secret("ZHIPU_API_KEY")
|
||||
|
||||
export const gateway = new sst.cloudflare.Worker("GatewayApi", {
|
||||
domain: `api.gateway.${domain}`,
|
||||
handler: "packages/function/src/gateway.ts",
|
||||
url: true,
|
||||
link: [OPENCODE_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, ZHIPU_API_KEY],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"plugin": ["./packages/plugin/src/example.ts"],
|
||||
"mcp": {
|
||||
"context7": {
|
||||
"type": "remote",
|
||||
|
||||
+2
-4
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"packageManager": "bun@1.2.14",
|
||||
"scripts": {
|
||||
"dev": "bun run --conditions=development packages/opencode/src/index.ts",
|
||||
"dev": "bun run packages/opencode/src/index.ts",
|
||||
"typecheck": "bun run --filter='*' typecheck",
|
||||
"stainless": "./scripts/stainless",
|
||||
"postinstall": "./script/hooks"
|
||||
@@ -43,7 +43,5 @@
|
||||
"protobufjs",
|
||||
"sharp"
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"marked-shiki@1.2.0": "patches/marked-shiki@1.2.0.patch"
|
||||
}
|
||||
"patchedDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
{
|
||||
"name": "@opencode/function",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0-202508022053",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "4.20250522.0",
|
||||
"@types/node": "catalog:",
|
||||
"openai": "5.11.0",
|
||||
"typescript": "catalog:"
|
||||
"typescript": "catalog:",
|
||||
"@types/node": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "2.0.0",
|
||||
"@ai-sdk/openai": "2.0.2",
|
||||
"@ai-sdk/openai-compatible": "1.0.1",
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"ai": "catalog:",
|
||||
"hono": "catalog:",
|
||||
"jose": "6.0.11"
|
||||
}
|
||||
|
||||
@@ -1,499 +0,0 @@
|
||||
import { Hono, Context, Next } from "hono"
|
||||
import { Resource } from "sst"
|
||||
import { generateText, streamText } from "ai"
|
||||
import { createAnthropic } from "@ai-sdk/anthropic"
|
||||
import { createOpenAI } from "@ai-sdk/openai"
|
||||
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
|
||||
import { type LanguageModelV2Prompt } from "@ai-sdk/provider"
|
||||
import { type ChatCompletionCreateParamsBase } from "openai/resources/chat/completions"
|
||||
|
||||
type Env = {}
|
||||
|
||||
const auth = async (c: Context, next: Next) => {
|
||||
const authHeader = c.req.header("authorization")
|
||||
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return c.json(
|
||||
{
|
||||
error: {
|
||||
message: "Missing API key.",
|
||||
type: "invalid_request_error",
|
||||
param: null,
|
||||
code: "unauthorized",
|
||||
},
|
||||
},
|
||||
401,
|
||||
)
|
||||
}
|
||||
|
||||
const apiKey = authHeader.split(" ")[1]
|
||||
|
||||
// Replace with your validation logic
|
||||
if (apiKey !== Resource.OPENCODE_API_KEY.value) {
|
||||
return c.json(
|
||||
{
|
||||
error: {
|
||||
message: "Invalid API key.",
|
||||
type: "invalid_request_error",
|
||||
param: null,
|
||||
code: "unauthorized",
|
||||
},
|
||||
},
|
||||
401,
|
||||
)
|
||||
}
|
||||
|
||||
await next()
|
||||
}
|
||||
export default new Hono<{ Bindings: Env }>()
|
||||
.get("/", (c) => c.text("Hello, world!"))
|
||||
.post("/v1/chat/completions", auth, async (c) => {
|
||||
try {
|
||||
const body = await c.req.json<ChatCompletionCreateParamsBase>()
|
||||
|
||||
console.log(body)
|
||||
|
||||
const model = (() => {
|
||||
const [provider, ...parts] = body.model.split("/")
|
||||
const model = parts.join("/")
|
||||
if (provider === "anthropic" && model === "claude-sonnet-4") {
|
||||
return createAnthropic({
|
||||
apiKey: Resource.ANTHROPIC_API_KEY.value,
|
||||
})("claude-sonnet-4-20250514")
|
||||
}
|
||||
if (provider === "openai" && model === "gpt-4.1") {
|
||||
return createOpenAI({
|
||||
apiKey: Resource.OPENAI_API_KEY.value,
|
||||
})("gpt-4.1")
|
||||
}
|
||||
if (provider === "zhipuai" && model === "glm-4.5-flash") {
|
||||
return createOpenAICompatible({
|
||||
name: "Zhipu AI",
|
||||
baseURL: "https://api.z.ai/api/paas/v4",
|
||||
apiKey: Resource.ZHIPU_API_KEY.value,
|
||||
})("glm-4.5-flash")
|
||||
}
|
||||
throw new Error(`Unsupported provider: ${provider}`)
|
||||
})()
|
||||
|
||||
const requestBody = transformOpenAIRequestToAiSDK()
|
||||
|
||||
return body.stream ? await handleStream() : await handleGenerate()
|
||||
|
||||
async function handleStream() {
|
||||
const result = await streamText({
|
||||
model,
|
||||
...requestBody,
|
||||
})
|
||||
|
||||
const encoder = new TextEncoder()
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const id = `chatcmpl-${Date.now()}`
|
||||
const created = Math.floor(Date.now() / 1000)
|
||||
|
||||
try {
|
||||
for await (const chunk of result.fullStream) {
|
||||
// TODO
|
||||
//console.log("!!! CHUCK !!!", chunk);
|
||||
switch (chunk.type) {
|
||||
case "text-delta": {
|
||||
const data = {
|
||||
id,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model: body.model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: {
|
||||
content: chunk.text,
|
||||
},
|
||||
finish_reason: null,
|
||||
},
|
||||
],
|
||||
}
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
|
||||
break
|
||||
}
|
||||
|
||||
case "reasoning-delta": {
|
||||
const data = {
|
||||
id,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model: body.model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: {
|
||||
reasoning_content: chunk.text,
|
||||
},
|
||||
finish_reason: null,
|
||||
},
|
||||
],
|
||||
}
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
|
||||
break
|
||||
}
|
||||
|
||||
case "tool-call": {
|
||||
const data = {
|
||||
id,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model: body.model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
id: chunk.toolCallId,
|
||||
type: "function",
|
||||
function: {
|
||||
name: chunk.toolName,
|
||||
arguments: JSON.stringify(chunk.input),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
finish_reason: null,
|
||||
},
|
||||
],
|
||||
}
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
|
||||
break
|
||||
}
|
||||
|
||||
case "error": {
|
||||
const data = {
|
||||
id,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model: body.model,
|
||||
error: {
|
||||
message: chunk.error,
|
||||
type: "server_error",
|
||||
},
|
||||
}
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
|
||||
controller.enqueue(encoder.encode("data: [DONE]\n\n"))
|
||||
controller.close()
|
||||
break
|
||||
}
|
||||
|
||||
case "finish": {
|
||||
const finishReason =
|
||||
{
|
||||
stop: "stop",
|
||||
length: "length",
|
||||
"content-filter": "content_filter",
|
||||
"tool-calls": "tool_calls",
|
||||
error: "stop",
|
||||
other: "stop",
|
||||
unknown: "stop",
|
||||
}[chunk.finishReason] || "stop"
|
||||
|
||||
const data = {
|
||||
id,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model: body.model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: {},
|
||||
finish_reason: finishReason,
|
||||
},
|
||||
],
|
||||
usage: {
|
||||
prompt_tokens: chunk.totalUsage.inputTokens,
|
||||
completion_tokens: chunk.totalUsage.outputTokens,
|
||||
total_tokens: chunk.totalUsage.totalTokens,
|
||||
completion_tokens_details: {
|
||||
reasoning_tokens: chunk.totalUsage.reasoningTokens,
|
||||
},
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: chunk.totalUsage.cachedInputTokens,
|
||||
},
|
||||
},
|
||||
}
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
|
||||
controller.enqueue(encoder.encode("data: [DONE]\n\n"))
|
||||
controller.close()
|
||||
break
|
||||
}
|
||||
|
||||
//case "stream-start":
|
||||
//case "response-metadata":
|
||||
case "start-step":
|
||||
case "finish-step":
|
||||
case "text-start":
|
||||
case "text-end":
|
||||
case "reasoning-start":
|
||||
case "reasoning-end":
|
||||
case "tool-input-start":
|
||||
case "tool-input-delta":
|
||||
case "tool-input-end":
|
||||
case "raw":
|
||||
default:
|
||||
// Log unknown chunk types for debugging
|
||||
console.warn(`Unknown chunk type: ${(chunk as any).type}`)
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return new Response(stream, {
|
||||
headers: {
|
||||
"Content-Type": "text/plain; charset=utf-8",
|
||||
"Cache-Control": "no-cache",
|
||||
Connection: "keep-alive",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function handleGenerate() {
|
||||
const response = await generateText({
|
||||
model,
|
||||
...requestBody,
|
||||
})
|
||||
return c.json({
|
||||
id: `chatcmpl-${Date.now()}`,
|
||||
object: "chat.completion" as const,
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
model: body.model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
message: {
|
||||
role: "assistant" as const,
|
||||
content: response.content?.find((c) => c.type === "text")?.text ?? "",
|
||||
reasoning_content: response.content?.find((c) => c.type === "reasoning")?.text,
|
||||
tool_calls: response.content
|
||||
?.filter((c) => c.type === "tool-call")
|
||||
.map((toolCall) => ({
|
||||
id: toolCall.toolCallId,
|
||||
type: "function" as const,
|
||||
function: {
|
||||
name: toolCall.toolName,
|
||||
arguments: toolCall.input,
|
||||
},
|
||||
})),
|
||||
},
|
||||
finish_reason:
|
||||
(
|
||||
{
|
||||
stop: "stop",
|
||||
length: "length",
|
||||
"content-filter": "content_filter",
|
||||
"tool-calls": "tool_calls",
|
||||
error: "stop",
|
||||
other: "stop",
|
||||
unknown: "stop",
|
||||
} as const
|
||||
)[response.finishReason] || "stop",
|
||||
},
|
||||
],
|
||||
usage: {
|
||||
prompt_tokens: response.usage?.inputTokens,
|
||||
completion_tokens: response.usage?.outputTokens,
|
||||
total_tokens: response.usage?.totalTokens,
|
||||
completion_tokens_details: {
|
||||
reasoning_tokens: response.usage?.reasoningTokens,
|
||||
},
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: response.usage?.cachedInputTokens,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function transformOpenAIRequestToAiSDK() {
|
||||
const prompt = transformMessages()
|
||||
|
||||
return {
|
||||
prompt,
|
||||
maxOutputTokens: body.max_tokens ?? body.max_completion_tokens ?? undefined,
|
||||
temperature: body.temperature ?? undefined,
|
||||
topP: body.top_p ?? undefined,
|
||||
frequencyPenalty: body.frequency_penalty ?? undefined,
|
||||
presencePenalty: body.presence_penalty ?? undefined,
|
||||
providerOptions: body.reasoning_effort
|
||||
? {
|
||||
anthropic: {
|
||||
reasoningEffort: body.reasoning_effort,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
stopSequences: (typeof body.stop === "string" ? [body.stop] : body.stop) ?? undefined,
|
||||
responseFormat: (() => {
|
||||
if (!body.response_format) return { type: "text" }
|
||||
if (body.response_format.type === "json_schema")
|
||||
return {
|
||||
type: "json",
|
||||
schema: body.response_format.json_schema.schema,
|
||||
name: body.response_format.json_schema.name,
|
||||
description: body.response_format.json_schema.description,
|
||||
}
|
||||
if (body.response_format.type === "json_object") return { type: "json" }
|
||||
throw new Error("Unsupported response format")
|
||||
})(),
|
||||
seed: body.seed ?? undefined,
|
||||
}
|
||||
|
||||
function transformTools() {
|
||||
const { tools, tool_choice } = body
|
||||
|
||||
if (!tools || tools.length === 0) {
|
||||
return { tools: undefined, toolChoice: undefined }
|
||||
}
|
||||
|
||||
const aiSdkTools = tools.reduce(
|
||||
(acc, tool) => {
|
||||
acc[tool.function.name] = {
|
||||
type: "function" as const,
|
||||
name: tool.function.name,
|
||||
description: tool.function.description,
|
||||
inputSchema: tool.function.parameters,
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
)
|
||||
|
||||
let aiSdkToolChoice
|
||||
if (tool_choice == null) {
|
||||
aiSdkToolChoice = undefined
|
||||
} else if (tool_choice === "auto") {
|
||||
aiSdkToolChoice = "auto"
|
||||
} else if (tool_choice === "none") {
|
||||
aiSdkToolChoice = "none"
|
||||
} else if (tool_choice === "required") {
|
||||
aiSdkToolChoice = "required"
|
||||
} else if (tool_choice.type === "function") {
|
||||
aiSdkToolChoice = {
|
||||
type: "tool",
|
||||
toolName: tool_choice.function.name,
|
||||
}
|
||||
}
|
||||
|
||||
return { tools: aiSdkTools, toolChoice: aiSdkToolChoice }
|
||||
}
|
||||
|
||||
function transformMessages() {
|
||||
const { messages } = body
|
||||
const prompt: LanguageModelV2Prompt = []
|
||||
|
||||
for (const message of messages) {
|
||||
switch (message.role) {
|
||||
case "system": {
|
||||
prompt.push({
|
||||
role: "system",
|
||||
content: message.content as string,
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case "user": {
|
||||
if (typeof message.content === "string") {
|
||||
prompt.push({
|
||||
role: "user",
|
||||
content: [{ type: "text", text: message.content }],
|
||||
})
|
||||
} else {
|
||||
const content = message.content.map((part) => {
|
||||
switch (part.type) {
|
||||
case "text":
|
||||
return { type: "text" as const, text: part.text }
|
||||
case "image_url":
|
||||
return {
|
||||
type: "file" as const,
|
||||
mediaType: "image/jpeg" as const,
|
||||
data: part.image_url.url,
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported content part type: ${(part as any).type}`)
|
||||
}
|
||||
})
|
||||
prompt.push({
|
||||
role: "user",
|
||||
content,
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "assistant": {
|
||||
const content: Array<
|
||||
| { type: "text"; text: string }
|
||||
| {
|
||||
type: "tool-call"
|
||||
toolCallId: string
|
||||
toolName: string
|
||||
input: any
|
||||
}
|
||||
> = []
|
||||
|
||||
if (message.content) {
|
||||
content.push({
|
||||
type: "text",
|
||||
text: message.content as string,
|
||||
})
|
||||
}
|
||||
|
||||
if (message.tool_calls) {
|
||||
for (const toolCall of message.tool_calls) {
|
||||
content.push({
|
||||
type: "tool-call",
|
||||
toolCallId: toolCall.id,
|
||||
toolName: toolCall.function.name,
|
||||
input: JSON.parse(toolCall.function.arguments),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
prompt.push({
|
||||
role: "assistant",
|
||||
content,
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case "tool": {
|
||||
prompt.push({
|
||||
role: "tool",
|
||||
content: [
|
||||
{
|
||||
type: "tool-result",
|
||||
toolName: "placeholder",
|
||||
toolCallId: message.tool_call_id,
|
||||
output: {
|
||||
type: "text",
|
||||
value: message.content as string,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(`Unsupported message role: ${message.role}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prompt
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
return c.json({ error: { message: error.message } }, 500)
|
||||
}
|
||||
})
|
||||
.all("*", (c) => c.text("Not Found"))
|
||||
Vendored
-17
@@ -6,10 +6,6 @@
|
||||
import "sst"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"ANTHROPIC_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"GITHUB_APP_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
@@ -18,22 +14,10 @@ declare module "sst" {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"OPENAI_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"OPENCODE_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"Web": {
|
||||
"type": "sst.cloudflare.Astro"
|
||||
"url": string
|
||||
}
|
||||
"ZHIPU_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
}
|
||||
}
|
||||
// cloudflare
|
||||
@@ -42,7 +26,6 @@ declare module "sst" {
|
||||
export interface Resource {
|
||||
"Api": cloudflare.Service
|
||||
"Bucket": cloudflare.R2Bucket
|
||||
"GatewayApi": cloudflare.Service
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0-202508022053",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run --conditions=development ./src/index.ts"
|
||||
"dev": "bun run ./src/index.ts"
|
||||
},
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode"
|
||||
@@ -37,7 +37,6 @@
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@openauthjs/openauth": "0.4.3",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@zip.js/zip.js": "2.7.62",
|
||||
"ai": "catalog:",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Log } from "../util/log"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { z } from "zod"
|
||||
import { App } from "../app/app"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
@@ -93,14 +92,6 @@ export namespace Config {
|
||||
throw new InvalidError({ path: item }, { cause: parsed.error })
|
||||
}
|
||||
|
||||
result.plugin = result.plugin || []
|
||||
result.plugin.push(
|
||||
...[
|
||||
...(await Filesystem.globUp("plugin/*.ts", Global.Path.config, Global.Path.config)),
|
||||
...(await Filesystem.globUp(".opencode/plugin/*.ts", app.path.cwd, app.path.root)),
|
||||
].map((x) => "file://" + x),
|
||||
)
|
||||
|
||||
// Handle migration from autoshare to share field
|
||||
if (result.autoshare === true && !result.share) {
|
||||
result.share = "auto"
|
||||
@@ -412,10 +403,7 @@ export namespace Config {
|
||||
if (lineIndex !== -1 && lines[lineIndex].trim().startsWith("//")) {
|
||||
continue // Skip if line is commented
|
||||
}
|
||||
let filePath = match.replace(/^\{file:/, "").replace(/\}$/, "")
|
||||
if (filePath.startsWith("~/")) {
|
||||
filePath = path.join(os.homedir(), filePath.slice(2))
|
||||
}
|
||||
const filePath = match.replace(/^\{file:/, "").replace(/\}$/, "")
|
||||
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
|
||||
const fileContent = (await Bun.file(resolvedPath).text()).trim()
|
||||
// escape newlines/quotes, strip outer quotes
|
||||
@@ -457,9 +445,9 @@ export namespace Config {
|
||||
if (data.plugin) {
|
||||
for (let i = 0; i < data.plugin?.length; i++) {
|
||||
const plugin = data.plugin[i]
|
||||
try {
|
||||
data.plugin[i] = import.meta.resolve(plugin, filepath)
|
||||
} catch (err) {}
|
||||
if (typeof plugin === "string") {
|
||||
data.plugin[i] = path.resolve(path.dirname(filepath), plugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
|
||||
@@ -83,7 +83,6 @@ const cli = yargs(hideBin(process.argv))
|
||||
if (msg.startsWith("Unknown argument") || msg.startsWith("Not enough non-option arguments")) {
|
||||
cli.showHelp("log")
|
||||
}
|
||||
process.exit(1)
|
||||
})
|
||||
.strict()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Bus } from "../bus"
|
||||
import { Log } from "../util/log"
|
||||
import { createOpencodeClient } from "@opencode-ai/sdk"
|
||||
import { Server } from "../server/server"
|
||||
import { BunProc } from "../bun"
|
||||
import { pathOr } from "remeda"
|
||||
|
||||
export namespace Plugin {
|
||||
const log = Log.create({ service: "plugin" })
|
||||
@@ -17,12 +17,8 @@ export namespace Plugin {
|
||||
})
|
||||
const config = await Config.get()
|
||||
const hooks = []
|
||||
for (let plugin of config.plugin ?? []) {
|
||||
for (const plugin of config.plugin ?? []) {
|
||||
log.info("loading plugin", { path: plugin })
|
||||
if (!plugin.startsWith("file://")) {
|
||||
const [pkg, version] = plugin.split("@")
|
||||
plugin = await BunProc.install(pkg, version ?? "latest")
|
||||
}
|
||||
const mod = await import(plugin)
|
||||
for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
|
||||
const init = await fn({
|
||||
@@ -39,18 +35,38 @@ export namespace Plugin {
|
||||
}
|
||||
})
|
||||
|
||||
type Path<T, Prefix extends string = ""> = T extends object
|
||||
? {
|
||||
[K in keyof T]: K extends string
|
||||
? T[K] extends Function | undefined
|
||||
? `${Prefix}${K}`
|
||||
: Path<T[K], `${Prefix}${K}.`>
|
||||
: never
|
||||
}[keyof T]
|
||||
: never
|
||||
|
||||
export type FunctionFromKey<T, P extends Path<T>> = P extends `${infer K}.${infer R}`
|
||||
? K extends keyof T
|
||||
? R extends Path<T[K]>
|
||||
? FunctionFromKey<T[K], R>
|
||||
: never
|
||||
: never
|
||||
: P extends keyof T
|
||||
? T[P]
|
||||
: never
|
||||
|
||||
export async function trigger<
|
||||
Name extends keyof Required<Hooks>,
|
||||
Input = Parameters<Required<Hooks>[Name]>[0],
|
||||
Output = Parameters<Required<Hooks>[Name]>[1],
|
||||
>(name: Name, input: Input, output: Output): Promise<Output> {
|
||||
if (!name) return output
|
||||
Name extends Path<Required<Hooks>>,
|
||||
Input = Parameters<FunctionFromKey<Required<Hooks>, Name>>[0],
|
||||
Output = Parameters<FunctionFromKey<Required<Hooks>, Name>>[1],
|
||||
>(fn: Name, input: Input, output: Output): Promise<Output> {
|
||||
if (!fn) return output
|
||||
const path = fn.split(".")
|
||||
for (const hook of await state().then((x) => x.hooks)) {
|
||||
const fn = hook[name]
|
||||
// @ts-expect-error
|
||||
const fn = pathOr(hook, path, undefined)
|
||||
if (!fn) continue
|
||||
// @ts-expect-error if you feel adventurous, please fix the typing, make sure to bump the try-counter if you
|
||||
// give up.
|
||||
// try-counter: 2
|
||||
// @ts-expect-error
|
||||
await fn(input, output)
|
||||
}
|
||||
return output
|
||||
|
||||
@@ -77,4 +77,4 @@ export namespace ModelsDev {
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(() => ModelsDev.refresh(), 60 * 1000 * 60).unref()
|
||||
setInterval(() => ModelsDev.refresh(), 60 * 1000).unref()
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
type ModelMessage,
|
||||
stepCountIs,
|
||||
type StreamTextResult,
|
||||
InvalidToolInputError,
|
||||
} from "ai"
|
||||
|
||||
import PROMPT_INITIALIZE from "../session/prompt/initialize.txt"
|
||||
@@ -736,9 +735,10 @@ export namespace Session {
|
||||
args,
|
||||
},
|
||||
)
|
||||
await processor.track(options.toolCallId)
|
||||
const result = await item.execute(args, {
|
||||
sessionID: input.sessionID,
|
||||
abort: options.abortSignal!,
|
||||
abort: abort.signal,
|
||||
messageID: assistantMsg.id,
|
||||
callID: options.toolCallId,
|
||||
metadata: async (val) => {
|
||||
@@ -780,10 +780,11 @@ export namespace Session {
|
||||
}
|
||||
|
||||
for (const [key, item] of Object.entries(await MCP.tools())) {
|
||||
if (enabledTools[key] === false) continue
|
||||
if (mode.tools[key] === false) continue
|
||||
const execute = item.execute
|
||||
if (!execute) continue
|
||||
item.execute = async (args, opts) => {
|
||||
await processor.track(opts.toolCallId)
|
||||
const result = await execute(args, opts)
|
||||
const output = result.content
|
||||
.filter((x: any) => x.type === "text")
|
||||
@@ -870,21 +871,7 @@ export namespace Session {
|
||||
messages,
|
||||
}
|
||||
},
|
||||
async experimental_repairToolCall(input) {
|
||||
if (InvalidToolInputError.isInstance(input.error)) {
|
||||
return {
|
||||
...input.toolCall,
|
||||
input: JSON.stringify({
|
||||
tool: input.toolCall.toolName,
|
||||
error: input.error.message,
|
||||
}),
|
||||
toolName: "invalid",
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
maxRetries: 3,
|
||||
activeTools: Object.keys(tools).filter((x) => x !== "invalid"),
|
||||
maxOutputTokens: outputLimit,
|
||||
abortSignal: abort.signal,
|
||||
stopWhen: stepCountIs(1000),
|
||||
@@ -933,11 +920,15 @@ export namespace Session {
|
||||
}
|
||||
|
||||
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
|
||||
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
||||
let snapshot: string | undefined
|
||||
const toolCalls: Record<string, MessageV2.ToolPart> = {}
|
||||
const snapshots: Record<string, string> = {}
|
||||
return {
|
||||
async track(toolCallID: string) {
|
||||
const hash = await Snapshot.track()
|
||||
if (hash) snapshots[toolCallID] = hash
|
||||
},
|
||||
partFromToolCall(toolCallID: string) {
|
||||
return toolcalls[toolCallID]
|
||||
return toolCalls[toolCallID]
|
||||
},
|
||||
async process(stream: StreamTextResult<Record<string, AITool>, never>) {
|
||||
try {
|
||||
@@ -953,7 +944,7 @@ export namespace Session {
|
||||
|
||||
case "tool-input-start":
|
||||
const part = await updatePart({
|
||||
id: toolcalls[value.id]?.id ?? Identifier.ascending("part"),
|
||||
id: toolCalls[value.id]?.id ?? Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "tool",
|
||||
@@ -963,7 +954,7 @@ export namespace Session {
|
||||
status: "pending",
|
||||
},
|
||||
})
|
||||
toolcalls[value.id] = part as MessageV2.ToolPart
|
||||
toolCalls[value.id] = part as MessageV2.ToolPart
|
||||
break
|
||||
|
||||
case "tool-input-delta":
|
||||
@@ -973,11 +964,10 @@ export namespace Session {
|
||||
break
|
||||
|
||||
case "tool-call": {
|
||||
const match = toolcalls[value.toolCallId]
|
||||
const match = toolCalls[value.toolCallId]
|
||||
if (match) {
|
||||
const part = await updatePart({
|
||||
...match,
|
||||
tool: value.toolName,
|
||||
state: {
|
||||
status: "running",
|
||||
input: value.input,
|
||||
@@ -986,12 +976,12 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
toolcalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
toolCalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
}
|
||||
break
|
||||
}
|
||||
case "tool-result": {
|
||||
const match = toolcalls[value.toolCallId]
|
||||
const match = toolCalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
await updatePart({
|
||||
...match,
|
||||
@@ -1007,13 +997,27 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
delete toolcalls[value.toolCallId]
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "tool-error": {
|
||||
const match = toolcalls[value.toolCallId]
|
||||
const match = toolCalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
await updatePart({
|
||||
...match,
|
||||
@@ -1027,7 +1031,19 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
delete toolcalls[value.toolCallId]
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -1042,7 +1058,6 @@ export namespace Session {
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "step-start",
|
||||
})
|
||||
snapshot = await Snapshot.track()
|
||||
break
|
||||
|
||||
case "finish-step":
|
||||
@@ -1058,20 +1073,6 @@ export namespace Session {
|
||||
cost: usage.cost,
|
||||
})
|
||||
await updateMessage(assistantMsg)
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
snapshot = undefined
|
||||
}
|
||||
break
|
||||
|
||||
case "text-start":
|
||||
@@ -1344,10 +1345,10 @@ export namespace Session {
|
||||
}
|
||||
return {
|
||||
cost: new Decimal(0)
|
||||
.add(new Decimal(tokens.input).mul(model.cost?.input?? 0).div(1_000_000))
|
||||
.add(new Decimal(tokens.output).mul(model.cost?.output?? 0).div(1_000_000))
|
||||
.add(new Decimal(tokens.cache.read).mul(model.cost?.cache_read ?? 0).div(1_000_000))
|
||||
.add(new Decimal(tokens.cache.write).mul(model.cost?.cache_write ?? 0).div(1_000_000))
|
||||
.add(new Decimal(tokens.input).mul(model.cost.input).div(1_000_000))
|
||||
.add(new Decimal(tokens.output).mul(model.cost.output).div(1_000_000))
|
||||
.add(new Decimal(tokens.cache.read).mul(model.cost.cache_read ?? 0).div(1_000_000))
|
||||
.add(new Decimal(tokens.cache.write).mul(model.cost.cache_write ?? 0).div(1_000_000))
|
||||
.toNumber(),
|
||||
tokens,
|
||||
}
|
||||
|
||||
@@ -60,28 +60,33 @@ export namespace SystemPrompt {
|
||||
export async function custom() {
|
||||
const { cwd, root } = App.info().path
|
||||
const config = await Config.get()
|
||||
const paths = new Set<string>()
|
||||
|
||||
const found = []
|
||||
for (const item of CUSTOM_FILES) {
|
||||
const matches = await Filesystem.findUp(item, cwd, root)
|
||||
matches.forEach((path) => paths.add(path))
|
||||
found.push(...matches.map((x) => Bun.file(x).text()))
|
||||
}
|
||||
|
||||
paths.add(path.join(Global.Path.config, "AGENTS.md"))
|
||||
paths.add(path.join(os.homedir(), ".claude", "CLAUDE.md"))
|
||||
|
||||
if (config.instructions) {
|
||||
for (const instruction of config.instructions) {
|
||||
const matches = await Filesystem.globUp(instruction, cwd, root).catch(() => [])
|
||||
matches.forEach((path) => paths.add(path))
|
||||
}
|
||||
}
|
||||
|
||||
const found = Array.from(paths).map((p) =>
|
||||
Bun.file(p)
|
||||
found.push(
|
||||
Bun.file(path.join(Global.Path.config, "AGENTS.md"))
|
||||
.text()
|
||||
.catch(() => ""),
|
||||
)
|
||||
found.push(
|
||||
Bun.file(path.join(os.homedir(), ".claude", "CLAUDE.md"))
|
||||
.text()
|
||||
.catch(() => ""),
|
||||
)
|
||||
|
||||
if (config.instructions) {
|
||||
for (const instruction of config.instructions) {
|
||||
try {
|
||||
const matches = await Filesystem.globUp(instruction, cwd, root)
|
||||
found.push(...matches.map((x) => Bun.file(x).text()))
|
||||
} catch {
|
||||
continue // Skip invalid glob patterns
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(found).then((result) => result.filter(Boolean))
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export namespace Snapshot {
|
||||
log.info("initialized")
|
||||
}
|
||||
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).nothrow().text()
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).text()
|
||||
return hash.trim()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { z } from "zod"
|
||||
import { exec } from "child_process"
|
||||
import { text } from "stream/consumers"
|
||||
import { Tool } from "./tool"
|
||||
import DESCRIPTION from "./bash.txt"
|
||||
import { App } from "../app/app"
|
||||
@@ -77,13 +75,9 @@ export const BashTool = Tool.define("bash", {
|
||||
if (["cd", "rm", "cp", "mv", "mkdir", "touch", "chmod", "chown"].includes(command[0])) {
|
||||
for (const arg of command.slice(1)) {
|
||||
if (arg.startsWith("-") || (command[0] === "chmod" && arg.startsWith("+"))) continue
|
||||
const resolved = await $`realpath ${arg}`
|
||||
.quiet()
|
||||
.nothrow()
|
||||
.text()
|
||||
.then((x) => x.trim())
|
||||
const resolved = await $`realpath ${arg}`.text().then((x) => x.trim())
|
||||
log.info("resolved path", { arg, resolved })
|
||||
if (resolved && !Filesystem.contains(app.path.cwd, resolved)) {
|
||||
if (!Filesystem.contains(app.path.cwd, resolved)) {
|
||||
throw new Error(
|
||||
`This command references paths outside of ${app.path.cwd} so it is not allowed to be executed.`,
|
||||
)
|
||||
@@ -118,24 +112,18 @@ export const BashTool = Tool.define("bash", {
|
||||
})
|
||||
}
|
||||
|
||||
const process = exec(params.command, {
|
||||
const process = Bun.spawn({
|
||||
cmd: ["bash", "-c", params.command],
|
||||
cwd: app.path.cwd,
|
||||
signal: ctx.abort,
|
||||
maxBuffer: MAX_OUTPUT_LENGTH,
|
||||
timeout,
|
||||
signal: ctx.abort,
|
||||
timeout: timeout,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
})
|
||||
|
||||
const stdoutPromise = text(process.stdout!)
|
||||
const stderrPromise = text(process.stderr!)
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
process.on("close", () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
|
||||
const stdout = await stdoutPromise
|
||||
const stderr = await stderrPromise
|
||||
await process.exited
|
||||
const stdout = await new Response(process.stdout).text()
|
||||
const stderr = await new Response(process.stderr).text()
|
||||
|
||||
return {
|
||||
title: params.command,
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { z } from "zod"
|
||||
import { Tool } from "./tool"
|
||||
|
||||
export const InvalidTool = Tool.define("invalid", {
|
||||
description: "Do not use",
|
||||
parameters: z.object({
|
||||
tool: z.string(),
|
||||
error: z.string(),
|
||||
}),
|
||||
async execute(params) {
|
||||
return {
|
||||
title: "Invalid Tool",
|
||||
output: `The arguments provided to the tool are invalid: ${params.error}`,
|
||||
metadata: {},
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -10,11 +10,9 @@ import { TaskTool } from "./task"
|
||||
import { TodoWriteTool, TodoReadTool } from "./todo"
|
||||
import { WebFetchTool } from "./webfetch"
|
||||
import { WriteTool } from "./write"
|
||||
import { InvalidTool } from "./invalid"
|
||||
|
||||
export namespace ToolRegistry {
|
||||
const ALL = [
|
||||
InvalidTool,
|
||||
BashTool,
|
||||
EditTool,
|
||||
WebFetchTool,
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@tsconfig/bun/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"customConditions": [
|
||||
"development"
|
||||
]
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"development": "./src/index.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:",
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@tsconfig/node22": "catalog:"
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { Plugin } from "./index"
|
||||
|
||||
export const ExamplePlugin: Plugin = async ({ app, client, $ }) => {
|
||||
export const ExamplePlugin: Plugin = async ({ app, client }) => {
|
||||
return {
|
||||
permission: {},
|
||||
async "chat.params"(input, output) {
|
||||
output.topP = 1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,56 @@
|
||||
import type { Event, createOpencodeClient, App, Model, Provider, Permission, UserMessage, Part } from "@opencode-ai/sdk"
|
||||
import type { BunShell } from "./shell"
|
||||
import { $ } from "bun"
|
||||
|
||||
export type PluginInput = {
|
||||
client: ReturnType<typeof createOpencodeClient>
|
||||
app: App
|
||||
$: BunShell
|
||||
$: $
|
||||
}
|
||||
export type Plugin = (input: PluginInput) => Promise<Hooks>
|
||||
|
||||
export interface Hooks {
|
||||
event?: (input: { event: Event }) => Promise<void>
|
||||
/**
|
||||
* Called when a new message is received
|
||||
*/
|
||||
"chat.message"?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
|
||||
/**
|
||||
* Modify parameters sent to LLM
|
||||
*/
|
||||
"chat.params"?: (
|
||||
input: { model: Model; provider: Provider; message: UserMessage },
|
||||
output: { temperature: number; topP: number },
|
||||
) => Promise<void>
|
||||
"permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
|
||||
"tool.execute.before"?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { args: any },
|
||||
) => Promise<void>
|
||||
"tool.execute.after"?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: {
|
||||
title: string
|
||||
output: string
|
||||
metadata: any
|
||||
},
|
||||
) => Promise<void>
|
||||
chat?: {
|
||||
/**
|
||||
* Called when a new message is received
|
||||
*/
|
||||
message?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
|
||||
/**
|
||||
* Modify parameters sent to LLM
|
||||
*/
|
||||
params?: (
|
||||
input: { model: Model; provider: Provider; message: UserMessage },
|
||||
output: { temperature: number; topP: number },
|
||||
) => Promise<void>
|
||||
}
|
||||
permission?: {
|
||||
/**
|
||||
* Called when a permission is asked
|
||||
*/
|
||||
ask?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
|
||||
}
|
||||
tool?: {
|
||||
execute?: {
|
||||
/**
|
||||
* Called before a tool is executed
|
||||
*/
|
||||
before?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: {
|
||||
args: any
|
||||
},
|
||||
) => Promise<void>
|
||||
/**
|
||||
* Called after a tool is executed
|
||||
*/
|
||||
after?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: {
|
||||
title: string
|
||||
output: string
|
||||
metadata: any
|
||||
},
|
||||
) => Promise<void>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
export type ShellFunction = (input: Uint8Array) => Uint8Array
|
||||
|
||||
export type ShellExpression =
|
||||
| { toString(): string }
|
||||
| Array<ShellExpression>
|
||||
| string
|
||||
| { raw: string }
|
||||
| ReadableStream
|
||||
|
||||
export interface BunShell {
|
||||
(strings: TemplateStringsArray, ...expressions: ShellExpression[]): BunShellPromise
|
||||
|
||||
/**
|
||||
* Perform bash-like brace expansion on the given pattern.
|
||||
* @param pattern - Brace pattern to expand
|
||||
*/
|
||||
braces(pattern: string): string[]
|
||||
|
||||
/**
|
||||
* Escape strings for input into shell commands.
|
||||
*/
|
||||
escape(input: string): string
|
||||
|
||||
/**
|
||||
* Change the default environment variables for shells created by this instance.
|
||||
*/
|
||||
env(newEnv?: Record<string, string | undefined>): BunShell
|
||||
|
||||
/**
|
||||
* Default working directory to use for shells created by this instance.
|
||||
*/
|
||||
cwd(newCwd?: string): BunShell
|
||||
|
||||
/**
|
||||
* Configure the shell to not throw an exception on non-zero exit codes.
|
||||
*/
|
||||
nothrow(): BunShell
|
||||
|
||||
/**
|
||||
* Configure whether or not the shell should throw an exception on non-zero exit codes.
|
||||
*/
|
||||
throws(shouldThrow: boolean): BunShell
|
||||
}
|
||||
|
||||
export interface BunShellPromise extends Promise<BunShellOutput> {
|
||||
readonly stdin: WritableStream
|
||||
|
||||
/**
|
||||
* Change the current working directory of the shell.
|
||||
*/
|
||||
cwd(newCwd: string): this
|
||||
|
||||
/**
|
||||
* Set environment variables for the shell.
|
||||
*/
|
||||
env(newEnv: Record<string, string> | undefined): this
|
||||
|
||||
/**
|
||||
* By default, the shell will write to the current process's stdout and stderr, as well as buffering that output.
|
||||
* This configures the shell to only buffer the output.
|
||||
*/
|
||||
quiet(): this
|
||||
|
||||
/**
|
||||
* Read from stdout as a string, line by line
|
||||
* Automatically calls quiet() to disable echoing to stdout.
|
||||
*/
|
||||
lines(): AsyncIterable<string>
|
||||
|
||||
/**
|
||||
* Read from stdout as a string.
|
||||
* Automatically calls quiet() to disable echoing to stdout.
|
||||
*/
|
||||
text(encoding?: BufferEncoding): Promise<string>
|
||||
|
||||
/**
|
||||
* Read from stdout as a JSON object
|
||||
* Automatically calls quiet()
|
||||
*/
|
||||
json(): Promise<any>
|
||||
|
||||
/**
|
||||
* Read from stdout as an ArrayBuffer
|
||||
* Automatically calls quiet()
|
||||
*/
|
||||
arrayBuffer(): Promise<ArrayBuffer>
|
||||
|
||||
/**
|
||||
* Read from stdout as a Blob
|
||||
* Automatically calls quiet()
|
||||
*/
|
||||
blob(): Promise<Blob>
|
||||
|
||||
/**
|
||||
* Configure the shell to not throw an exception on non-zero exit codes.
|
||||
*/
|
||||
nothrow(): this
|
||||
|
||||
/**
|
||||
* Configure whether or not the shell should throw an exception on non-zero exit codes.
|
||||
*/
|
||||
throws(shouldThrow: boolean): this
|
||||
}
|
||||
|
||||
export interface BunShellOutput {
|
||||
readonly stdout: Buffer
|
||||
readonly stderr: Buffer
|
||||
readonly exitCode: number
|
||||
|
||||
/**
|
||||
* Read from stdout as a string
|
||||
*/
|
||||
text(encoding?: BufferEncoding): string
|
||||
|
||||
/**
|
||||
* Read from stdout as a JSON object
|
||||
*/
|
||||
json(): any
|
||||
|
||||
/**
|
||||
* Read from stdout as an ArrayBuffer
|
||||
*/
|
||||
arrayBuffer(): ArrayBuffer
|
||||
|
||||
/**
|
||||
* Read from stdout as an Uint8Array
|
||||
*/
|
||||
bytes(): Uint8Array
|
||||
|
||||
/**
|
||||
* Read from stdout as a Blob
|
||||
*/
|
||||
blob(): Blob
|
||||
}
|
||||
|
||||
export type BunShellError = Error & BunShellOutput
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
/* This file is auto-generated by SST. Do not edit. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* deno-fmt-ignore-file */
|
||||
|
||||
/// <reference path="../../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'generated'
|
||||
- 'codegen/**'
|
||||
- 'integrated/**'
|
||||
- 'stl-preview-head/**'
|
||||
- 'stl-preview-base/**'
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- 'stl-preview-head/**'
|
||||
- 'stl-preview-base/**'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
timeout-minutes: 10
|
||||
name: lint
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/opencode-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Bootstrap
|
||||
run: ./scripts/bootstrap
|
||||
|
||||
- name: Check types
|
||||
run: ./scripts/lint
|
||||
|
||||
build:
|
||||
timeout-minutes: 5
|
||||
name: build
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/opencode-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Bootstrap
|
||||
run: ./scripts/bootstrap
|
||||
|
||||
- name: Check build
|
||||
run: ./scripts/build
|
||||
|
||||
- name: Get GitHub OIDC Token
|
||||
if: github.repository == 'stainless-sdks/opencode-typescript'
|
||||
id: github-oidc
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: core.setOutput('github_token', await core.getIDToken());
|
||||
|
||||
- name: Upload tarball
|
||||
if: github.repository == 'stainless-sdks/opencode-typescript'
|
||||
env:
|
||||
URL: https://pkg.stainless.com/s
|
||||
AUTH: ${{ steps.github-oidc.outputs.github_token }}
|
||||
SHA: ${{ github.sha }}
|
||||
run: ./scripts/utils/upload-artifact.sh
|
||||
test:
|
||||
timeout-minutes: 10
|
||||
name: test
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/opencode-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Bootstrap
|
||||
run: ./scripts/bootstrap
|
||||
|
||||
- name: Run tests
|
||||
run: ./scripts/test
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# This workflow is triggered when a GitHub release is created.
|
||||
# It can also be run manually to re-publish to NPM in case it failed for some reason.
|
||||
# You can run this workflow by navigating to https://www.github.com/sst/opencode-sdk-js/actions/workflows/publish-npm.yml
|
||||
name: Publish NPM
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
yarn install
|
||||
|
||||
- name: Publish to NPM
|
||||
run: |
|
||||
bash ./bin/publish-npm
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.OPENCODE_NPM_TOKEN || secrets.NPM_TOKEN }}
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Release Doctor
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release_doctor:
|
||||
name: release doctor
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'sst/opencode-sdk-js' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check release environment
|
||||
run: |
|
||||
bash ./bin/check-release-environment
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.OPENCODE_NPM_TOKEN || secrets.NPM_TOKEN }}
|
||||
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 34
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-52fd0b61e84fdc1cdd31ec12e1600510e9dd2f9d4fb20c2315b4975cb763ee98.yml
|
||||
openapi_spec_hash: e851b8d5a2412f5fc9be82ab88ebdfde
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-2ebd9d5478864042a2e01b4995f42acbc39069fa7fcccd1c2e567366ee6c243d.yml
|
||||
openapi_spec_hash: 2a34451b288ea30af1cb61332c417c2a
|
||||
config_hash: 11a6f0803eb407367c3f677d3e524c37
|
||||
|
||||
@@ -151,7 +151,6 @@ type Mode struct {
|
||||
Model ModeModel `json:"model"`
|
||||
Prompt string `json:"prompt"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
TopP float64 `json:"topP"`
|
||||
JSON modeJSON `json:"-"`
|
||||
}
|
||||
|
||||
@@ -162,7 +161,6 @@ type modeJSON struct {
|
||||
Model apijson.Field
|
||||
Prompt apijson.Field
|
||||
Temperature apijson.Field
|
||||
TopP apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
+3
-170
@@ -51,16 +51,14 @@ type Config struct {
|
||||
// Automatically update to the latest version
|
||||
Autoupdate bool `json:"autoupdate"`
|
||||
// Disable providers that are loaded automatically
|
||||
DisabledProviders []string `json:"disabled_providers"`
|
||||
Experimental ConfigExperimental `json:"experimental"`
|
||||
Formatter map[string]ConfigFormatter `json:"formatter"`
|
||||
DisabledProviders []string `json:"disabled_providers"`
|
||||
Experimental ConfigExperimental `json:"experimental"`
|
||||
// Additional instruction files or patterns to include
|
||||
Instructions []string `json:"instructions"`
|
||||
// Custom keybind configurations
|
||||
Keybinds KeybindsConfig `json:"keybinds"`
|
||||
// @deprecated Always uses stretch layout.
|
||||
Layout ConfigLayout `json:"layout"`
|
||||
Lsp map[string]ConfigLsp `json:"lsp"`
|
||||
Layout ConfigLayout `json:"layout"`
|
||||
// MCP (Model Context Protocol) server configurations
|
||||
Mcp map[string]ConfigMcp `json:"mcp"`
|
||||
// Modes configuration, see https://opencode.ai/docs/modes
|
||||
@@ -68,7 +66,6 @@ type Config struct {
|
||||
// Model to use in the format of provider/model, eg anthropic/claude-2
|
||||
Model string `json:"model"`
|
||||
Permission ConfigPermission `json:"permission"`
|
||||
Plugin []string `json:"plugin"`
|
||||
// Custom provider configurations and model overrides
|
||||
Provider map[string]ConfigProvider `json:"provider"`
|
||||
// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
|
||||
@@ -92,16 +89,13 @@ type configJSON struct {
|
||||
Autoupdate apijson.Field
|
||||
DisabledProviders apijson.Field
|
||||
Experimental apijson.Field
|
||||
Formatter apijson.Field
|
||||
Instructions apijson.Field
|
||||
Keybinds apijson.Field
|
||||
Layout apijson.Field
|
||||
Lsp apijson.Field
|
||||
Mcp apijson.Field
|
||||
Mode apijson.Field
|
||||
Model apijson.Field
|
||||
Permission apijson.Field
|
||||
Plugin apijson.Field
|
||||
Provider apijson.Field
|
||||
Share apijson.Field
|
||||
SmallModel apijson.Field
|
||||
@@ -253,32 +247,6 @@ func (r configExperimentalHookSessionCompletedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type ConfigFormatter struct {
|
||||
Command []string `json:"command"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Environment map[string]string `json:"environment"`
|
||||
Extensions []string `json:"extensions"`
|
||||
JSON configFormatterJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configFormatterJSON contains the JSON metadata for the struct [ConfigFormatter]
|
||||
type configFormatterJSON struct {
|
||||
Command apijson.Field
|
||||
Disabled apijson.Field
|
||||
Environment apijson.Field
|
||||
Extensions apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigFormatter) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configFormatterJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
// @deprecated Always uses stretch layout.
|
||||
type ConfigLayout string
|
||||
|
||||
@@ -295,139 +263,6 @@ func (r ConfigLayout) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type ConfigLsp struct {
|
||||
// This field can have the runtime type of [[]string].
|
||||
Command interface{} `json:"command"`
|
||||
Disabled bool `json:"disabled"`
|
||||
// This field can have the runtime type of [map[string]string].
|
||||
Env interface{} `json:"env"`
|
||||
// This field can have the runtime type of [[]string].
|
||||
Extensions interface{} `json:"extensions"`
|
||||
// This field can have the runtime type of [map[string]interface{}].
|
||||
Initialization interface{} `json:"initialization"`
|
||||
JSON configLspJSON `json:"-"`
|
||||
union ConfigLspUnion
|
||||
}
|
||||
|
||||
// configLspJSON contains the JSON metadata for the struct [ConfigLsp]
|
||||
type configLspJSON struct {
|
||||
Command apijson.Field
|
||||
Disabled apijson.Field
|
||||
Env apijson.Field
|
||||
Extensions apijson.Field
|
||||
Initialization apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r configLspJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r *ConfigLsp) UnmarshalJSON(data []byte) (err error) {
|
||||
*r = ConfigLsp{}
|
||||
err = apijson.UnmarshalRoot(data, &r.union)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return apijson.Port(r.union, &r)
|
||||
}
|
||||
|
||||
// AsUnion returns a [ConfigLspUnion] interface which you can cast to the specific
|
||||
// types for more type safety.
|
||||
//
|
||||
// Possible runtime types of the union are [ConfigLspDisabled], [ConfigLspObject].
|
||||
func (r ConfigLsp) AsUnion() ConfigLspUnion {
|
||||
return r.union
|
||||
}
|
||||
|
||||
// Union satisfied by [ConfigLspDisabled] or [ConfigLspObject].
|
||||
type ConfigLspUnion interface {
|
||||
implementsConfigLsp()
|
||||
}
|
||||
|
||||
func init() {
|
||||
apijson.RegisterUnion(
|
||||
reflect.TypeOf((*ConfigLspUnion)(nil)).Elem(),
|
||||
"",
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(ConfigLspDisabled{}),
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(ConfigLspObject{}),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type ConfigLspDisabled struct {
|
||||
Disabled ConfigLspDisabledDisabled `json:"disabled,required"`
|
||||
JSON configLspDisabledJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configLspDisabledJSON contains the JSON metadata for the struct
|
||||
// [ConfigLspDisabled]
|
||||
type configLspDisabledJSON struct {
|
||||
Disabled apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigLspDisabled) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configLspDisabledJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r ConfigLspDisabled) implementsConfigLsp() {}
|
||||
|
||||
type ConfigLspDisabledDisabled bool
|
||||
|
||||
const (
|
||||
ConfigLspDisabledDisabledTrue ConfigLspDisabledDisabled = true
|
||||
)
|
||||
|
||||
func (r ConfigLspDisabledDisabled) IsKnown() bool {
|
||||
switch r {
|
||||
case ConfigLspDisabledDisabledTrue:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ConfigLspObject struct {
|
||||
Command []string `json:"command,required"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Env map[string]string `json:"env"`
|
||||
Extensions []string `json:"extensions"`
|
||||
Initialization map[string]interface{} `json:"initialization"`
|
||||
JSON configLspObjectJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configLspObjectJSON contains the JSON metadata for the struct [ConfigLspObject]
|
||||
type configLspObjectJSON struct {
|
||||
Command apijson.Field
|
||||
Disabled apijson.Field
|
||||
Env apijson.Field
|
||||
Extensions apijson.Field
|
||||
Initialization apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigLspObject) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configLspObjectJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r ConfigLspObject) implementsConfigLsp() {}
|
||||
|
||||
type ConfigMcp struct {
|
||||
// Type of MCP server connection
|
||||
Type ConfigMcpType `json:"type,required"`
|
||||
@@ -1029,7 +864,6 @@ type ModeConfig struct {
|
||||
Prompt string `json:"prompt"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
Tools map[string]bool `json:"tools"`
|
||||
TopP float64 `json:"top_p"`
|
||||
JSON modeConfigJSON `json:"-"`
|
||||
}
|
||||
|
||||
@@ -1040,7 +874,6 @@ type modeConfigJSON struct {
|
||||
Prompt apijson.Field
|
||||
Temperature apijson.Field
|
||||
Tools apijson.Field
|
||||
TopP apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
+121
-123
@@ -54,13 +54,13 @@ type EventListResponse struct {
|
||||
// [EventListResponseEventMessageRemovedProperties],
|
||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||
// [EventListResponseEventMessagePartRemovedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties],
|
||||
// [EventListResponseEventFileEditedProperties], [interface{}], [Permission],
|
||||
// [EventListResponseEventStorageWriteProperties], [Permission],
|
||||
// [EventListResponseEventPermissionRepliedProperties],
|
||||
// [EventListResponseEventFileEditedProperties],
|
||||
// [EventListResponseEventSessionUpdatedProperties],
|
||||
// [EventListResponseEventSessionDeletedProperties],
|
||||
// [EventListResponseEventSessionIdleProperties],
|
||||
// [EventListResponseEventSessionErrorProperties],
|
||||
// [EventListResponseEventSessionErrorProperties], [interface{}],
|
||||
// [EventListResponseEventFileWatcherUpdatedProperties],
|
||||
// [EventListResponseEventIdeInstalledProperties].
|
||||
Properties interface{} `json:"properties,required"`
|
||||
@@ -100,12 +100,11 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventFileWatcherUpdated],
|
||||
// [EventListResponseEventIdeInstalled].
|
||||
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
@@ -117,12 +116,11 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventFileWatcherUpdated] or
|
||||
// [EventListResponseEventIdeInstalled].
|
||||
type EventListResponseUnion interface {
|
||||
@@ -168,16 +166,6 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventStorageWrite{}),
|
||||
DiscriminatorValue: "storage.write",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
||||
DiscriminatorValue: "file.edited",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
||||
DiscriminatorValue: "server.connected",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
||||
@@ -188,6 +176,11 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
|
||||
DiscriminatorValue: "permission.replied",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
||||
DiscriminatorValue: "file.edited",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}),
|
||||
@@ -208,6 +201,11 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventSessionError{}),
|
||||
DiscriminatorValue: "session.error",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
||||
DiscriminatorValue: "server.connected",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileWatcherUpdated{}),
|
||||
@@ -651,105 +649,6 @@ func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEdited struct {
|
||||
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileEditedType `json:"type,required"`
|
||||
JSON eventListResponseEventFileEditedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedJSON contains the JSON metadata for the struct
|
||||
// [EventListResponseEventFileEdited]
|
||||
type eventListResponseEventFileEditedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEdited) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventFileEdited) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventFileEditedProperties struct {
|
||||
File string `json:"file,required"`
|
||||
JSON eventListResponseEventFileEditedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedPropertiesJSON contains the JSON metadata for
|
||||
// the struct [EventListResponseEventFileEditedProperties]
|
||||
type eventListResponseEventFileEditedPropertiesJSON struct {
|
||||
File apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEditedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEditedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventFileEditedTypeFileEdited EventListResponseEventFileEditedType = "file.edited"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventFileEditedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventFileEditedTypeFileEdited:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventServerConnected struct {
|
||||
Properties interface{} `json:"properties,required"`
|
||||
Type EventListResponseEventServerConnectedType `json:"type,required"`
|
||||
JSON eventListResponseEventServerConnectedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventServerConnectedJSON contains the JSON metadata for the
|
||||
// struct [EventListResponseEventServerConnected]
|
||||
type eventListResponseEventServerConnectedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventServerConnected) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventServerConnectedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventServerConnected) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventServerConnectedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventServerConnectedTypeServerConnected EventListResponseEventServerConnectedType = "server.connected"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventServerConnectedTypeServerConnected:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdated struct {
|
||||
Properties Permission `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||
@@ -853,6 +752,66 @@ func (r EventListResponseEventPermissionRepliedType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEdited struct {
|
||||
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileEditedType `json:"type,required"`
|
||||
JSON eventListResponseEventFileEditedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedJSON contains the JSON metadata for the struct
|
||||
// [EventListResponseEventFileEdited]
|
||||
type eventListResponseEventFileEditedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEdited) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventFileEdited) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventFileEditedProperties struct {
|
||||
File string `json:"file,required"`
|
||||
JSON eventListResponseEventFileEditedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedPropertiesJSON contains the JSON metadata for
|
||||
// the struct [EventListResponseEventFileEditedProperties]
|
||||
type eventListResponseEventFileEditedPropertiesJSON struct {
|
||||
File apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEditedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEditedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventFileEditedTypeFileEdited EventListResponseEventFileEditedType = "file.edited"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventFileEditedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventFileEditedTypeFileEdited:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventSessionUpdated struct {
|
||||
Properties EventListResponseEventSessionUpdatedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventSessionUpdatedType `json:"type,required"`
|
||||
@@ -1229,6 +1188,45 @@ func (r EventListResponseEventSessionErrorType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventServerConnected struct {
|
||||
Properties interface{} `json:"properties,required"`
|
||||
Type EventListResponseEventServerConnectedType `json:"type,required"`
|
||||
JSON eventListResponseEventServerConnectedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventServerConnectedJSON contains the JSON metadata for the
|
||||
// struct [EventListResponseEventServerConnected]
|
||||
type eventListResponseEventServerConnectedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventServerConnected) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventServerConnectedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventServerConnected) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventServerConnectedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventServerConnectedTypeServerConnected EventListResponseEventServerConnectedType = "server.connected"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventServerConnectedTypeServerConnected:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileWatcherUpdated struct {
|
||||
Properties EventListResponseEventFileWatcherUpdatedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileWatcherUpdatedType `json:"type,required"`
|
||||
@@ -1376,21 +1374,21 @@ const (
|
||||
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
||||
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
||||
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
||||
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
||||
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
|
||||
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
|
||||
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
|
||||
EventListResponseTypeSessionError EventListResponseType = "session.error"
|
||||
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
||||
EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated"
|
||||
EventListResponseTypeIdeInstalled EventListResponseType = "ide.installed"
|
||||
)
|
||||
|
||||
func (r EventListResponseType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypeFileEdited, EventListResponseTypeServerConnected, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0-202508022053",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
|
||||
@@ -4,11 +4,16 @@ const dir = new URL("..", import.meta.url).pathname
|
||||
process.chdir(dir)
|
||||
|
||||
import { $ } from "bun"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
|
||||
console.log("=== Generating JS SDK ===")
|
||||
console.log()
|
||||
|
||||
import { createClient } from "@hey-api/openapi-ts"
|
||||
|
||||
await $`bun dev generate > ${dir}/openapi.json`.cwd(path.resolve(dir, "../../opencode"))
|
||||
await fs.rm(path.join(dir, "src/gen"), { recursive: true, force: true })
|
||||
await $`bun run ../../opencode/src/index.ts generate > openapi.json`
|
||||
|
||||
await createClient({
|
||||
input: "./openapi.json",
|
||||
@@ -32,3 +37,6 @@ await createClient({
|
||||
],
|
||||
})
|
||||
await $`bun prettier --write src/gen`
|
||||
|
||||
await $`rm -rf dist`
|
||||
await $`bun tsc`
|
||||
|
||||
@@ -6,8 +6,6 @@ process.chdir(dir)
|
||||
import { $ } from "bun"
|
||||
|
||||
await import("./generate")
|
||||
await $`rm -rf dist`
|
||||
await $`bun tsc`
|
||||
|
||||
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
|
||||
|
||||
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
/* This file is auto-generated by SST. Do not edit. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* deno-fmt-ignore-file */
|
||||
|
||||
/// <reference path="../../../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
@@ -7,12 +7,8 @@
|
||||
"declaration": true,
|
||||
"moduleResolution": "bundler",
|
||||
"lib": [
|
||||
"es2022",
|
||||
"dom",
|
||||
"dom.iterable"
|
||||
],
|
||||
"customConditions": [
|
||||
"development"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
export {
|
||||
Permissions,
|
||||
type Permission,
|
||||
type PermissionRespondResponse,
|
||||
type PermissionRespondParams,
|
||||
} from './permissions';
|
||||
export {
|
||||
SessionResource,
|
||||
type AssistantMessage,
|
||||
type FilePart,
|
||||
type FilePartInput,
|
||||
type FilePartSource,
|
||||
type FilePartSourceText,
|
||||
type FileSource,
|
||||
type Message,
|
||||
type Part,
|
||||
type Session,
|
||||
type SnapshotPart,
|
||||
type StepFinishPart,
|
||||
type StepStartPart,
|
||||
type SymbolSource,
|
||||
type TextPart,
|
||||
type TextPartInput,
|
||||
type ToolPart,
|
||||
type ToolStateCompleted,
|
||||
type ToolStateError,
|
||||
type ToolStatePending,
|
||||
type ToolStateRunning,
|
||||
type UserMessage,
|
||||
type SessionListResponse,
|
||||
type SessionDeleteResponse,
|
||||
type SessionAbortResponse,
|
||||
type SessionInitResponse,
|
||||
type SessionMessageResponse,
|
||||
type SessionMessagesResponse,
|
||||
type SessionSummarizeResponse,
|
||||
type SessionChatParams,
|
||||
type SessionInitParams,
|
||||
type SessionMessageParams,
|
||||
type SessionRevertParams,
|
||||
type SessionSummarizeParams,
|
||||
} from './session';
|
||||
@@ -0,0 +1,64 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import { APIResource } from '../../core/resource';
|
||||
import { APIPromise } from '../../core/api-promise';
|
||||
import { RequestOptions } from '../../internal/request-options';
|
||||
import { path } from '../../internal/utils/path';
|
||||
|
||||
export class Permissions extends APIResource {
|
||||
/**
|
||||
* Respond to a permission request
|
||||
*/
|
||||
respond(
|
||||
permissionID: string,
|
||||
params: PermissionRespondParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<PermissionRespondResponse> {
|
||||
const { id, ...body } = params;
|
||||
return this._client.post(path`/session/${id}/permissions/${permissionID}`, { body, ...options });
|
||||
}
|
||||
}
|
||||
|
||||
export interface Permission {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
metadata: { [key: string]: unknown };
|
||||
|
||||
sessionID: string;
|
||||
|
||||
time: Permission.Time;
|
||||
|
||||
title: string;
|
||||
|
||||
toolCallID?: string;
|
||||
}
|
||||
|
||||
export namespace Permission {
|
||||
export interface Time {
|
||||
created: number;
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionRespondResponse = boolean;
|
||||
|
||||
export interface PermissionRespondParams {
|
||||
/**
|
||||
* Path param:
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Body param:
|
||||
*/
|
||||
response: 'once' | 'always' | 'reject';
|
||||
}
|
||||
|
||||
export declare namespace Permissions {
|
||||
export {
|
||||
type Permission as Permission,
|
||||
type PermissionRespondResponse as PermissionRespondResponse,
|
||||
type PermissionRespondParams as PermissionRespondParams,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,645 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import { APIResource } from '../../core/resource';
|
||||
import * as SessionAPI from './session';
|
||||
import * as Shared from '../shared';
|
||||
import * as PermissionsAPI from './permissions';
|
||||
import { Permission, PermissionRespondParams, PermissionRespondResponse, Permissions } from './permissions';
|
||||
import { APIPromise } from '../../core/api-promise';
|
||||
import { RequestOptions } from '../../internal/request-options';
|
||||
import { path } from '../../internal/utils/path';
|
||||
|
||||
export class SessionResource extends APIResource {
|
||||
permissions: PermissionsAPI.Permissions = new PermissionsAPI.Permissions(this._client);
|
||||
|
||||
/**
|
||||
* Create a new session
|
||||
*/
|
||||
create(options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post('/session', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all sessions
|
||||
*/
|
||||
list(options?: RequestOptions): APIPromise<SessionListResponse> {
|
||||
return this._client.get('/session', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a session and all its data
|
||||
*/
|
||||
delete(id: string, options?: RequestOptions): APIPromise<SessionDeleteResponse> {
|
||||
return this._client.delete(path`/session/${id}`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a session
|
||||
*/
|
||||
abort(id: string, options?: RequestOptions): APIPromise<SessionAbortResponse> {
|
||||
return this._client.post(path`/session/${id}/abort`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send a new message to a session
|
||||
*/
|
||||
chat(id: string, body: SessionChatParams, options?: RequestOptions): APIPromise<AssistantMessage> {
|
||||
return this._client.post(path`/session/${id}/message`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze the app and create an AGENTS.md file
|
||||
*/
|
||||
init(id: string, body: SessionInitParams, options?: RequestOptions): APIPromise<SessionInitResponse> {
|
||||
return this._client.post(path`/session/${id}/init`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message from a session
|
||||
*/
|
||||
message(
|
||||
messageID: string,
|
||||
params: SessionMessageParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<SessionMessageResponse> {
|
||||
const { id } = params;
|
||||
return this._client.get(path`/session/${id}/message/${messageID}`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List messages for a session
|
||||
*/
|
||||
messages(id: string, options?: RequestOptions): APIPromise<SessionMessagesResponse> {
|
||||
return this._client.get(path`/session/${id}/message`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert a message
|
||||
*/
|
||||
revert(id: string, body: SessionRevertParams, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/revert`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Share a session
|
||||
*/
|
||||
share(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/share`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Summarize the session
|
||||
*/
|
||||
summarize(
|
||||
id: string,
|
||||
body: SessionSummarizeParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<SessionSummarizeResponse> {
|
||||
return this._client.post(path`/session/${id}/summarize`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore all reverted messages
|
||||
*/
|
||||
unrevert(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/unrevert`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare the session
|
||||
*/
|
||||
unshare(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.delete(path`/session/${id}/share`, options);
|
||||
}
|
||||
}
|
||||
|
||||
export interface AssistantMessage {
|
||||
id: string;
|
||||
|
||||
cost: number;
|
||||
|
||||
mode: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
path: AssistantMessage.Path;
|
||||
|
||||
providerID: string;
|
||||
|
||||
role: 'assistant';
|
||||
|
||||
sessionID: string;
|
||||
|
||||
system: Array<string>;
|
||||
|
||||
time: AssistantMessage.Time;
|
||||
|
||||
tokens: AssistantMessage.Tokens;
|
||||
|
||||
error?:
|
||||
| Shared.ProviderAuthError
|
||||
| Shared.UnknownError
|
||||
| AssistantMessage.MessageOutputLengthError
|
||||
| Shared.MessageAbortedError;
|
||||
|
||||
summary?: boolean;
|
||||
}
|
||||
|
||||
export namespace AssistantMessage {
|
||||
export interface Path {
|
||||
cwd: string;
|
||||
|
||||
root: string;
|
||||
}
|
||||
|
||||
export interface Time {
|
||||
created: number;
|
||||
|
||||
completed?: number;
|
||||
}
|
||||
|
||||
export interface Tokens {
|
||||
cache: Tokens.Cache;
|
||||
|
||||
input: number;
|
||||
|
||||
output: number;
|
||||
|
||||
reasoning: number;
|
||||
}
|
||||
|
||||
export namespace Tokens {
|
||||
export interface Cache {
|
||||
read: number;
|
||||
|
||||
write: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface MessageOutputLengthError {
|
||||
data: unknown;
|
||||
|
||||
name: 'MessageOutputLengthError';
|
||||
}
|
||||
}
|
||||
|
||||
export interface FilePart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
mime: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'file';
|
||||
|
||||
url: string;
|
||||
|
||||
filename?: string;
|
||||
|
||||
source?: FilePartSource;
|
||||
}
|
||||
|
||||
export interface FilePartInput {
|
||||
mime: string;
|
||||
|
||||
type: 'file';
|
||||
|
||||
url: string;
|
||||
|
||||
id?: string;
|
||||
|
||||
filename?: string;
|
||||
|
||||
source?: FilePartSource;
|
||||
}
|
||||
|
||||
export type FilePartSource = FileSource | SymbolSource;
|
||||
|
||||
export interface FilePartSourceText {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface FileSource {
|
||||
path: string;
|
||||
|
||||
text: FilePartSourceText;
|
||||
|
||||
type: 'file';
|
||||
}
|
||||
|
||||
export type Message = UserMessage | AssistantMessage;
|
||||
|
||||
export type Part =
|
||||
| TextPart
|
||||
| FilePart
|
||||
| ToolPart
|
||||
| StepStartPart
|
||||
| StepFinishPart
|
||||
| SnapshotPart
|
||||
| Part.PatchPart;
|
||||
|
||||
export namespace Part {
|
||||
export interface PatchPart {
|
||||
id: string;
|
||||
|
||||
files: Array<string>;
|
||||
|
||||
hash: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'patch';
|
||||
}
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
|
||||
time: Session.Time;
|
||||
|
||||
title: string;
|
||||
|
||||
version: string;
|
||||
|
||||
parentID?: string;
|
||||
|
||||
revert?: Session.Revert;
|
||||
|
||||
share?: Session.Share;
|
||||
}
|
||||
|
||||
export namespace Session {
|
||||
export interface Time {
|
||||
created: number;
|
||||
|
||||
updated: number;
|
||||
}
|
||||
|
||||
export interface Revert {
|
||||
messageID: string;
|
||||
|
||||
diff?: string;
|
||||
|
||||
partID?: string;
|
||||
|
||||
snapshot?: string;
|
||||
}
|
||||
|
||||
export interface Share {
|
||||
url: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface SnapshotPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
snapshot: string;
|
||||
|
||||
type: 'snapshot';
|
||||
}
|
||||
|
||||
export interface StepFinishPart {
|
||||
id: string;
|
||||
|
||||
cost: number;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
tokens: StepFinishPart.Tokens;
|
||||
|
||||
type: 'step-finish';
|
||||
}
|
||||
|
||||
export namespace StepFinishPart {
|
||||
export interface Tokens {
|
||||
cache: Tokens.Cache;
|
||||
|
||||
input: number;
|
||||
|
||||
output: number;
|
||||
|
||||
reasoning: number;
|
||||
}
|
||||
|
||||
export namespace Tokens {
|
||||
export interface Cache {
|
||||
read: number;
|
||||
|
||||
write: number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface StepStartPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'step-start';
|
||||
}
|
||||
|
||||
export interface SymbolSource {
|
||||
kind: number;
|
||||
|
||||
name: string;
|
||||
|
||||
path: string;
|
||||
|
||||
range: SymbolSource.Range;
|
||||
|
||||
text: FilePartSourceText;
|
||||
|
||||
type: 'symbol';
|
||||
}
|
||||
|
||||
export namespace SymbolSource {
|
||||
export interface Range {
|
||||
end: Range.End;
|
||||
|
||||
start: Range.Start;
|
||||
}
|
||||
|
||||
export namespace Range {
|
||||
export interface End {
|
||||
character: number;
|
||||
|
||||
line: number;
|
||||
}
|
||||
|
||||
export interface Start {
|
||||
character: number;
|
||||
|
||||
line: number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface TextPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
text: string;
|
||||
|
||||
type: 'text';
|
||||
|
||||
synthetic?: boolean;
|
||||
|
||||
time?: TextPart.Time;
|
||||
}
|
||||
|
||||
export namespace TextPart {
|
||||
export interface Time {
|
||||
start: number;
|
||||
|
||||
end?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface TextPartInput {
|
||||
text: string;
|
||||
|
||||
type: 'text';
|
||||
|
||||
id?: string;
|
||||
|
||||
synthetic?: boolean;
|
||||
|
||||
time?: TextPartInput.Time;
|
||||
}
|
||||
|
||||
export namespace TextPartInput {
|
||||
export interface Time {
|
||||
start: number;
|
||||
|
||||
end?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolPart {
|
||||
id: string;
|
||||
|
||||
callID: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
state: ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError;
|
||||
|
||||
tool: string;
|
||||
|
||||
type: 'tool';
|
||||
}
|
||||
|
||||
export interface ToolStateCompleted {
|
||||
input: { [key: string]: unknown };
|
||||
|
||||
metadata: { [key: string]: unknown };
|
||||
|
||||
output: string;
|
||||
|
||||
status: 'completed';
|
||||
|
||||
time: ToolStateCompleted.Time;
|
||||
|
||||
title: string;
|
||||
}
|
||||
|
||||
export namespace ToolStateCompleted {
|
||||
export interface Time {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolStateError {
|
||||
error: string;
|
||||
|
||||
input: { [key: string]: unknown };
|
||||
|
||||
status: 'error';
|
||||
|
||||
time: ToolStateError.Time;
|
||||
}
|
||||
|
||||
export namespace ToolStateError {
|
||||
export interface Time {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolStatePending {
|
||||
status: 'pending';
|
||||
}
|
||||
|
||||
export interface ToolStateRunning {
|
||||
status: 'running';
|
||||
|
||||
time: ToolStateRunning.Time;
|
||||
|
||||
input?: unknown;
|
||||
|
||||
metadata?: { [key: string]: unknown };
|
||||
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export namespace ToolStateRunning {
|
||||
export interface Time {
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserMessage {
|
||||
id: string;
|
||||
|
||||
role: 'user';
|
||||
|
||||
sessionID: string;
|
||||
|
||||
time: UserMessage.Time;
|
||||
}
|
||||
|
||||
export namespace UserMessage {
|
||||
export interface Time {
|
||||
created: number;
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionListResponse = Array<Session>;
|
||||
|
||||
export type SessionDeleteResponse = boolean;
|
||||
|
||||
export type SessionAbortResponse = boolean;
|
||||
|
||||
export type SessionInitResponse = boolean;
|
||||
|
||||
export interface SessionMessageResponse {
|
||||
info: Message;
|
||||
|
||||
parts: Array<Part>;
|
||||
}
|
||||
|
||||
export type SessionMessagesResponse = Array<SessionMessagesResponse.SessionMessagesResponseItem>;
|
||||
|
||||
export namespace SessionMessagesResponse {
|
||||
export interface SessionMessagesResponseItem {
|
||||
info: SessionAPI.Message;
|
||||
|
||||
parts: Array<SessionAPI.Part>;
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSummarizeResponse = boolean;
|
||||
|
||||
export interface SessionChatParams {
|
||||
modelID: string;
|
||||
|
||||
parts: Array<TextPartInput | FilePartInput>;
|
||||
|
||||
providerID: string;
|
||||
|
||||
messageID?: string;
|
||||
|
||||
mode?: string;
|
||||
|
||||
system?: string;
|
||||
|
||||
tools?: { [key: string]: boolean };
|
||||
}
|
||||
|
||||
export interface SessionInitParams {
|
||||
messageID: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
providerID: string;
|
||||
}
|
||||
|
||||
export interface SessionMessageParams {
|
||||
/**
|
||||
* Session ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface SessionRevertParams {
|
||||
messageID: string;
|
||||
|
||||
partID?: string;
|
||||
}
|
||||
|
||||
export interface SessionSummarizeParams {
|
||||
modelID: string;
|
||||
|
||||
providerID: string;
|
||||
}
|
||||
|
||||
SessionResource.Permissions = Permissions;
|
||||
|
||||
export declare namespace SessionResource {
|
||||
export {
|
||||
type AssistantMessage as AssistantMessage,
|
||||
type FilePart as FilePart,
|
||||
type FilePartInput as FilePartInput,
|
||||
type FilePartSource as FilePartSource,
|
||||
type FilePartSourceText as FilePartSourceText,
|
||||
type FileSource as FileSource,
|
||||
type Message as Message,
|
||||
type Part as Part,
|
||||
type Session as Session,
|
||||
type SnapshotPart as SnapshotPart,
|
||||
type StepFinishPart as StepFinishPart,
|
||||
type StepStartPart as StepStartPart,
|
||||
type SymbolSource as SymbolSource,
|
||||
type TextPart as TextPart,
|
||||
type TextPartInput as TextPartInput,
|
||||
type ToolPart as ToolPart,
|
||||
type ToolStateCompleted as ToolStateCompleted,
|
||||
type ToolStateError as ToolStateError,
|
||||
type ToolStatePending as ToolStatePending,
|
||||
type ToolStateRunning as ToolStateRunning,
|
||||
type UserMessage as UserMessage,
|
||||
type SessionListResponse as SessionListResponse,
|
||||
type SessionDeleteResponse as SessionDeleteResponse,
|
||||
type SessionAbortResponse as SessionAbortResponse,
|
||||
type SessionInitResponse as SessionInitResponse,
|
||||
type SessionMessageResponse as SessionMessageResponse,
|
||||
type SessionMessagesResponse as SessionMessagesResponse,
|
||||
type SessionSummarizeResponse as SessionSummarizeResponse,
|
||||
type SessionChatParams as SessionChatParams,
|
||||
type SessionInitParams as SessionInitParams,
|
||||
type SessionMessageParams as SessionMessageParams,
|
||||
type SessionRevertParams as SessionRevertParams,
|
||||
type SessionSummarizeParams as SessionSummarizeParams,
|
||||
};
|
||||
|
||||
export {
|
||||
Permissions as Permissions,
|
||||
type Permission as Permission,
|
||||
type PermissionRespondResponse as PermissionRespondResponse,
|
||||
type PermissionRespondParams as PermissionRespondParams,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import Opencode from '@opencode-ai/sdk';
|
||||
|
||||
const client = new Opencode({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010' });
|
||||
|
||||
describe('resource permissions', () => {
|
||||
// skipped: tests are disabled for the time being
|
||||
test.skip('respond: only required params', async () => {
|
||||
const responsePromise = client.session.permissions.respond('permissionID', {
|
||||
id: 'id',
|
||||
response: 'once',
|
||||
});
|
||||
const rawResponse = await responsePromise.asResponse();
|
||||
expect(rawResponse).toBeInstanceOf(Response);
|
||||
const response = await responsePromise;
|
||||
expect(response).not.toBeInstanceOf(Response);
|
||||
const dataAndResponse = await responsePromise.withResponse();
|
||||
expect(dataAndResponse.data).toBe(response);
|
||||
expect(dataAndResponse.response).toBe(rawResponse);
|
||||
});
|
||||
|
||||
// skipped: tests are disabled for the time being
|
||||
test.skip('respond: required and optional params', async () => {
|
||||
const response = await client.session.permissions.respond('permissionID', { id: 'id', response: 'once' });
|
||||
});
|
||||
});
|
||||
@@ -555,8 +555,6 @@ func renderToolName(name string) string {
|
||||
switch name {
|
||||
case "webfetch":
|
||||
return "Fetch"
|
||||
case "invalid":
|
||||
return "Invalid"
|
||||
default:
|
||||
normalizedName := name
|
||||
if after, ok := strings.CutPrefix(name, "opencode_"); ok {
|
||||
@@ -659,10 +657,6 @@ func renderToolTitle(
|
||||
title = getTodoTitle(toolCall)
|
||||
case "todoread":
|
||||
return "Plan"
|
||||
case "invalid":
|
||||
if actualTool, ok := toolArgsMap["tool"].(string); ok {
|
||||
title = renderToolName(actualTool)
|
||||
}
|
||||
default:
|
||||
toolName := renderToolName(toolCall.Tool)
|
||||
title = fmt.Sprintf("%s %s", toolName, toolArgs)
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/theme.json",
|
||||
"defs": {
|
||||
"vesperBg": "#101010",
|
||||
"vesperFg": "#FFF",
|
||||
"vesperComment": "#8b8b8b94",
|
||||
"vesperKeyword": "#A0A0A0",
|
||||
"vesperFunction": "#FFC799",
|
||||
"vesperString": "#99FFE4",
|
||||
"vesperNumber": "#FFC799",
|
||||
"vesperError": "#FF8080",
|
||||
"vesperWarning": "#FFC799",
|
||||
"vesperSuccess": "#99FFE4",
|
||||
"vesperMuted": "#A0A0A0"
|
||||
},
|
||||
"theme": {
|
||||
"primary": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"secondary": {
|
||||
"dark": "#99FFE4",
|
||||
"light": "#99FFE4"
|
||||
},
|
||||
"accent": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"error": {
|
||||
"dark": "vesperError",
|
||||
"light": "vesperError"
|
||||
},
|
||||
"warning": {
|
||||
"dark": "vesperWarning",
|
||||
"light": "vesperWarning"
|
||||
},
|
||||
"success": {
|
||||
"dark": "vesperSuccess",
|
||||
"light": "vesperSuccess"
|
||||
},
|
||||
"info": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"text": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"textMuted": {
|
||||
"dark": "vesperMuted",
|
||||
"light": "vesperMuted"
|
||||
},
|
||||
"background": {
|
||||
"dark": "vesperBg",
|
||||
"light": "#FFF"
|
||||
},
|
||||
"backgroundPanel": {
|
||||
"dark": "vesperBg",
|
||||
"light": "#F0F0F0"
|
||||
},
|
||||
"backgroundElement": {
|
||||
"dark": "vesperBg",
|
||||
"light": "#E0E0E0"
|
||||
},
|
||||
"border": {
|
||||
"dark": "#282828",
|
||||
"light": "#D0D0D0"
|
||||
},
|
||||
"borderActive": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"borderSubtle": {
|
||||
"dark": "#1C1C1C",
|
||||
"light": "#E8E8E8"
|
||||
},
|
||||
"diffAdded": {
|
||||
"dark": "vesperSuccess",
|
||||
"light": "vesperSuccess"
|
||||
},
|
||||
"diffRemoved": {
|
||||
"dark": "vesperError",
|
||||
"light": "vesperError"
|
||||
},
|
||||
"diffContext": {
|
||||
"dark": "vesperMuted",
|
||||
"light": "vesperMuted"
|
||||
},
|
||||
"diffHunkHeader": {
|
||||
"dark": "vesperMuted",
|
||||
"light": "vesperMuted"
|
||||
},
|
||||
"diffHighlightAdded": {
|
||||
"dark": "vesperSuccess",
|
||||
"light": "vesperSuccess"
|
||||
},
|
||||
"diffHighlightRemoved": {
|
||||
"dark": "vesperError",
|
||||
"light": "vesperError"
|
||||
},
|
||||
"diffAddedBg": {
|
||||
"dark": "#0d2818",
|
||||
"light": "#e8f5e8"
|
||||
},
|
||||
"diffRemovedBg": {
|
||||
"dark": "#281a1a",
|
||||
"light": "#f5e8e8"
|
||||
},
|
||||
"diffContextBg": {
|
||||
"dark": "vesperBg",
|
||||
"light": "#F8F8F8"
|
||||
},
|
||||
"diffLineNumber": {
|
||||
"dark": "#505050",
|
||||
"light": "#808080"
|
||||
},
|
||||
"diffAddedLineNumberBg": {
|
||||
"dark": "#0d2818",
|
||||
"light": "#e8f5e8"
|
||||
},
|
||||
"diffRemovedLineNumberBg": {
|
||||
"dark": "#281a1a",
|
||||
"light": "#f5e8e8"
|
||||
},
|
||||
"markdownText": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"markdownHeading": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"markdownLink": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"markdownLinkText": {
|
||||
"dark": "vesperMuted",
|
||||
"light": "vesperMuted"
|
||||
},
|
||||
"markdownCode": {
|
||||
"dark": "vesperMuted",
|
||||
"light": "vesperMuted"
|
||||
},
|
||||
"markdownBlockQuote": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"markdownEmph": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"markdownStrong": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"markdownHorizontalRule": {
|
||||
"dark": "#65737E",
|
||||
"light": "#65737E"
|
||||
},
|
||||
"markdownListItem": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"markdownListEnumeration": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"markdownImage": {
|
||||
"dark": "#FFC799",
|
||||
"light": "#FFC799"
|
||||
},
|
||||
"markdownImageText": {
|
||||
"dark": "vesperMuted",
|
||||
"light": "vesperMuted"
|
||||
},
|
||||
"markdownCodeBlock": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"syntaxComment": {
|
||||
"dark": "vesperComment",
|
||||
"light": "vesperComment"
|
||||
},
|
||||
"syntaxKeyword": {
|
||||
"dark": "vesperKeyword",
|
||||
"light": "vesperKeyword"
|
||||
},
|
||||
"syntaxFunction": {
|
||||
"dark": "vesperFunction",
|
||||
"light": "vesperFunction"
|
||||
},
|
||||
"syntaxVariable": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
},
|
||||
"syntaxString": {
|
||||
"dark": "vesperString",
|
||||
"light": "vesperString"
|
||||
},
|
||||
"syntaxNumber": {
|
||||
"dark": "vesperNumber",
|
||||
"light": "vesperNumber"
|
||||
},
|
||||
"syntaxType": {
|
||||
"dark": "vesperFunction",
|
||||
"light": "vesperFunction"
|
||||
},
|
||||
"syntaxOperator": {
|
||||
"dark": "vesperKeyword",
|
||||
"light": "vesperKeyword"
|
||||
},
|
||||
"syntaxPunctuation": {
|
||||
"dark": "vesperFg",
|
||||
"light": "vesperBg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,12 +80,11 @@ export default defineConfig({
|
||||
"docs/agents",
|
||||
"docs/models",
|
||||
"docs/themes",
|
||||
"docs/plugins",
|
||||
"docs/keybinds",
|
||||
"docs/formatters",
|
||||
"docs/permissions",
|
||||
"docs/lsp",
|
||||
"docs/mcp-servers",
|
||||
"docs/formatters",
|
||||
"docs/lsp",
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode/web",
|
||||
"type": "module",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0-202508022053",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "sst shell --stage=dev --target=Web astro dev",
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
# Disallow shared content pages
|
||||
Disallow: /s/
|
||||
@@ -230,20 +230,6 @@ You can also define agents using markdown files in `~/.config/opencode/agent/` o
|
||||
|
||||
You can disable providers that are loaded automatically through the `disabled_providers` option. This is useful when you want to prevent certain providers from being loaded even if their credentials are available.
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"disabled_providers": ["openai", "gemini"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Formatters
|
||||
@@ -253,21 +239,16 @@ You can configure code formatters through the `formatter` option. See [Formatter
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": {
|
||||
"prettier": {
|
||||
"disabled": true
|
||||
},
|
||||
"custom-prettier": {
|
||||
"command": ["npx", "prettier", "--write", "$FILE"],
|
||||
"environment": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"extensions": [".js", ".ts", ".jsx", ".tsx"]
|
||||
}
|
||||
}
|
||||
"disabled_providers": ["openai", "gemini"]
|
||||
}
|
||||
```
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
---
|
||||
title: Formatters
|
||||
description: opencode uses language specific formatters.
|
||||
description: Code formatting with opencode
|
||||
---
|
||||
|
||||
opencode automatically formats files after they are written or edited using language-specific formatters. This ensures that the code that is generated follows the code styles of your project.
|
||||
opencode automatically formats code files after they are written or edited using language-specific formatters. This ensures consistent code style across your project without manual intervention.
|
||||
|
||||
---
|
||||
## Built-in Formatters
|
||||
|
||||
## Built-in
|
||||
opencode comes with several built-in formatters for popular languages and frameworks:
|
||||
|
||||
opencode comes with several built-in formatters for popular languages and frameworks. Below is a list of the formatters, supported file extensions, and commands or config options it needs.
|
||||
|
||||
| Formatter | Extensions | Requirements |
|
||||
| Formatter | Languages/Extensions | Requirements |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------- |
|
||||
| gofmt | .go | `gofmt` command available |
|
||||
| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available |
|
||||
| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in `package.json` |
|
||||
| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in package.json |
|
||||
| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json` config file |
|
||||
| zig | .zig, .zon | `zig` command available |
|
||||
| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file |
|
||||
@@ -25,51 +23,17 @@ opencode comes with several built-in formatters for popular languages and framew
|
||||
| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available |
|
||||
| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available |
|
||||
|
||||
So if your project has `prettier` in your `package.json`, opencode will automatically use it.
|
||||
Formatters are automatically enabled when their requirements are met in your project environment.
|
||||
|
||||
---
|
||||
## Configuration
|
||||
|
||||
## How it works
|
||||
You can customize formatters through the `formatter` section in your `opencode.json` configuration file.
|
||||
|
||||
When opencode writes or edits a file, it:
|
||||
### Disabling Formatters
|
||||
|
||||
1. Checks the file extension against all enabled formatters.
|
||||
2. Runs the appropriate formatter command on the file.
|
||||
3. Applies the formatting changes automatically.
|
||||
|
||||
This process happens in the background, ensuring your code styles are maintained without any manual steps.
|
||||
|
||||
---
|
||||
|
||||
## Configure
|
||||
|
||||
You can customize formatters through the `formatter` section in your opencode config.
|
||||
To disable a specific formatter, set its `disabled` property to `true`:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": { }
|
||||
}
|
||||
```
|
||||
|
||||
Each formatter configuration supports the following:
|
||||
|
||||
| Property | Type | Description |
|
||||
| ------------- | -------- | ------------------------------------------------------- |
|
||||
| `disabled` | boolean | Set this to `true` to disable the formatter |
|
||||
| `command` | string[] | The command to run for formatting |
|
||||
| `environment` | object | Environment variables to set when running the formatter |
|
||||
| `extensions` | string[] | File extensions this formatter should handle |
|
||||
|
||||
Let's look at some examples.
|
||||
|
||||
---
|
||||
|
||||
### Disabling formatters
|
||||
|
||||
To disable a specific formatter, set `disabled` to `true`:
|
||||
|
||||
```json title="opencode.json" {5}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": {
|
||||
@@ -80,13 +44,11 @@ To disable a specific formatter, set `disabled` to `true`:
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
### Custom Formatters
|
||||
|
||||
### Custom formatters
|
||||
You can override the default formatters or add new ones by specifying the command, environment variables, and file extensions:
|
||||
|
||||
You can override the built-in formatters or add new ones by specifying the command, environment variables, and file extensions:
|
||||
|
||||
```json title="opencode.json" {4-10}
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": {
|
||||
@@ -101,4 +63,25 @@ You can override the built-in formatters or add new ones by specifying the comma
|
||||
}
|
||||
```
|
||||
|
||||
The **`$FILE` placeholder** in the command will be replaced with the path to the file being formatted.
|
||||
The `$FILE` placeholder in the command will be replaced with the path to the file being formatted.
|
||||
|
||||
### Configuration Options
|
||||
|
||||
Each formatter configuration supports these properties:
|
||||
|
||||
| Property | Type | Description |
|
||||
| ------------- | -------- | ------------------------------------------------------- |
|
||||
| `disabled` | boolean | Set to `true` to disable the formatter |
|
||||
| `command` | string[] | The command to run for formatting |
|
||||
| `environment` | object | Environment variables to set when running the formatter |
|
||||
| `extensions` | string[] | File extensions this formatter should handle |
|
||||
|
||||
## How It Works
|
||||
|
||||
When opencode writes or edits a file, it:
|
||||
|
||||
1. Checks the file extension against all enabled formatters
|
||||
2. Runs the appropriate formatter command on the file
|
||||
3. Applies the formatting changes automatically
|
||||
|
||||
This process happens seamlessly in the background, ensuring your code maintains consistent formatting without requiring manual steps.
|
||||
|
||||
@@ -106,7 +106,7 @@ Here are some examples of how you can use opencode in GitHub.
|
||||
|
||||
And opencode will create a new branch, implement the changes, and open a PR with the changes.
|
||||
|
||||
- **Review PRs and make changes**
|
||||
- Review PRs and make changes
|
||||
|
||||
Leave the following comment on a GitHub PR.
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
---
|
||||
title: LSP Servers
|
||||
description: opencode integrates with your LSP servers.
|
||||
description: Language Server Protocol integration with opencode
|
||||
---
|
||||
|
||||
opencode integrates with your Language Server Protocol (LSP) to help the LLM interacts with your codebase. It uses diagnostics to provide feebdack to the LLM. And _go-to-definition_ and _find-references_ to help navigate your codebase.
|
||||
opencode integrates with Language Server Protocol (LSP) to enhance how the LLM interacts with your codebase. LSP servers provide intelligent code analysis and editing capabilities for different programming languages.
|
||||
|
||||
---
|
||||
|
||||
## Built-in
|
||||
## Built-in LSP Servers
|
||||
|
||||
opencode comes with several built-in LSP servers for popular languages:
|
||||
|
||||
| LSP Server | Extensions | Requirements |
|
||||
| LSP Server | Languages/Extensions | Requirements |
|
||||
| ---------- | -------------------------------------------- | ----------------------------------- |
|
||||
| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project |
|
||||
| gopls | .go | `go` command available |
|
||||
@@ -21,49 +19,17 @@ opencode comes with several built-in LSP servers for popular languages:
|
||||
| zls | .zig, .zon | `zig` command available |
|
||||
| csharp | .cs | `.NET SDK` installed |
|
||||
|
||||
LSP servers are automatically enabled when one of the above file extensions are detected and the requirements are met.
|
||||
LSP servers are automatically enabled when their requirements are met in your project environment.
|
||||
|
||||
---
|
||||
## Configuration
|
||||
|
||||
## How It Works
|
||||
You can customize LSP servers through the `lsp` section in your `opencode.json` configuration file.
|
||||
|
||||
When opencode opens a file, it:
|
||||
### Disabling LSP Servers
|
||||
|
||||
1. Checks the file extension against all enabled LSP servers.
|
||||
2. Starts the appropriate LSP server if not already running.
|
||||
|
||||
---
|
||||
|
||||
## Configure
|
||||
|
||||
You can customize LSP servers through the `lsp` section in your opencode config.
|
||||
To disable a specific LSP server, set its configuration to `{ "disabled": true }`:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": { }
|
||||
}
|
||||
```
|
||||
|
||||
Each LSP server supports the following:
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------------- | -------- | ------------------------------------------------- |
|
||||
| `disabled` | boolean | Set this to `true` to disable the LSP server |
|
||||
| `command` | string[] | The command to start the LSP server |
|
||||
| `extensions` | string[] | File extensions this LSP server should handle |
|
||||
| `env` | object | Environment variables to set when starting server |
|
||||
| `initialization` | object | Initialization options to send to the LSP server |
|
||||
|
||||
Let's look at some examples.
|
||||
|
||||
---
|
||||
|
||||
### Disabling LSP servers
|
||||
|
||||
To disable a specific LSP server, set `disabled` to `true`:
|
||||
|
||||
```json title="opencode.json" {5}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": {
|
||||
@@ -74,13 +40,11 @@ To disable a specific LSP server, set `disabled` to `true`:
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Custom LSP servers
|
||||
### Custom LSP Servers
|
||||
|
||||
You can add custom LSP servers by specifying the command and file extensions:
|
||||
|
||||
```json title="opencode.json" {4-7}
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": {
|
||||
@@ -91,3 +55,25 @@ You can add custom LSP servers by specifying the command and file extensions:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
Each LSP server configuration supports these properties:
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------------- | -------- | ------------------------------------------------- |
|
||||
| `disabled` | boolean | Set to `true` to disable the LSP server |
|
||||
| `command` | string[] | The command to start the LSP server |
|
||||
| `extensions` | string[] | File extensions this LSP server should handle |
|
||||
| `env` | object | Environment variables to set when starting server |
|
||||
| `initialization` | object | Initialization options to send to the LSP server |
|
||||
|
||||
## How It Works
|
||||
|
||||
When opencode opens a file, it:
|
||||
|
||||
1. Checks the file extension against all enabled LSP servers
|
||||
2. Starts the appropriate LSP server if not already running
|
||||
3. Provides intelligent code analysis and editing capabilities
|
||||
|
||||
This integration allows the LLM to better understand your codebase through features like diagnostics, go-to-definition, and find-references.
|
||||
|
||||
@@ -16,8 +16,6 @@ Once added, MCP tools are automatically available to the LLM alongside built-in
|
||||
|
||||
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.
|
||||
@@ -45,8 +43,6 @@ Add local MCP servers using `"type": "local"` within the MCP object. Multiple MC
|
||||
|
||||
You can also disable a server by setting `enabled` to `false`. This is useful if you want to temporarily disable a server without removing it from your config.
|
||||
|
||||
---
|
||||
|
||||
### Remote
|
||||
|
||||
Add remote MCP servers under `mcp` with `"type": "remote"`.
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
title: Plugins
|
||||
description: Write your own plugins to extend opencode.
|
||||
---
|
||||
|
||||
Plugins allow you to extend opencode by hooking into various events and customizing behavior. You can create plugins to add new features, integrate with external services, or modify opencode's default behavior.
|
||||
|
||||
---
|
||||
|
||||
## Create a plugin
|
||||
|
||||
A plugin is a **JavaScript/TypeScript module** that exports one or more plugin
|
||||
functions. Each function receives a context object and returns a hooks object.
|
||||
|
||||
---
|
||||
|
||||
### Location
|
||||
|
||||
Plugins are loaded from:
|
||||
|
||||
1. `.opencode/plugin` directory either in your proejct
|
||||
2. Or, globally in `~/.config/opencode/plugin`
|
||||
|
||||
---
|
||||
|
||||
### Basic structure
|
||||
|
||||
```js title=".opencode/plugin/example.js"
|
||||
export const MyPlugin = async ({ app, client, $ }) => {
|
||||
console.log("Plugin initialized!")
|
||||
|
||||
return {
|
||||
// Hook implementations go here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The plugin function receives:
|
||||
|
||||
- `app`: The opencode application instance.
|
||||
- `client`: An opencode SDK client for interacting with the AI.
|
||||
- `$`: Bun's [shell API](https://bun.com/docs/runtime/shell) for executing commands.
|
||||
|
||||
---
|
||||
|
||||
### TypeScript support
|
||||
|
||||
For TypeScript plugins, you can import types from the plugin package:
|
||||
|
||||
```ts title="my-plugin.ts" {1}
|
||||
import type { Plugin } from "@opencode-ai/plugin"
|
||||
|
||||
export const MyPlugin: Plugin = async ({ app, client, $ }) => {
|
||||
return {
|
||||
// Type-safe hook implementations
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
Here are some examples of plugins you can use to extend opencode.
|
||||
|
||||
---
|
||||
|
||||
### Send notifications
|
||||
|
||||
Send notifications when certain events occur:
|
||||
|
||||
```js title=".opencode/plugin/notification.js"
|
||||
export const NotificationPlugin = async ({ client, $ }) => {
|
||||
return {
|
||||
event: async ({ event }) => {
|
||||
// Send notification on session completion
|
||||
if (event.type === "session.idle") {
|
||||
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here `osascript` is a command that runs on macOS and sends notifications.
|
||||
|
||||
---
|
||||
|
||||
### .env protection
|
||||
|
||||
Prevent opencode from reading `.env` files:
|
||||
|
||||
```javascript title=".opencode/plugin/slack.js"
|
||||
export const EnvProtection = async ({ client, $ }) => {
|
||||
return {
|
||||
tool: {
|
||||
execute: {
|
||||
before: async (input, output) => {
|
||||
if (input.tool === "read" && output.args.filePath.includes(".env")) {
|
||||
throw new Error("Do not read .env files")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -331,6 +331,7 @@ Or if you already have an API key, you can select **Manually enter API Key** and
|
||||
|
||||
1. Head over to the [Cerebras console](https://inference.cerebras.ai/), create an account, and generate an API key.
|
||||
|
||||
|
||||
2. Run `opencode auth login` and select **Cerebras**.
|
||||
|
||||
```bash
|
||||
@@ -588,7 +589,7 @@ To use Kimi K2 from Moonshot AI:
|
||||
|
||||
5. Configure Moonshot in your opencode config.
|
||||
|
||||
```json title="opencode.json" ""moonshot"" {5-15}
|
||||
```json title="opencode.json" "\"moonshot\"" {5-15}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
@@ -795,42 +796,6 @@ https://platform.openai.com/api-keys
|
||||
|
||||
---
|
||||
|
||||
### Zhipu AI
|
||||
|
||||
1. Head over to the [Zhipu API console](https://z.ai/manage-apikey/apikey-list), create an account, and click **Create a new API key**.
|
||||
|
||||
2. Run `opencode auth login` and select **Zhipu AI**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ● Zhipu AI
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
3. Enter your Zhipu AI API key.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Zhipu AI
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ _
|
||||
└
|
||||
```
|
||||
|
||||
4. Run the `/models` command to select a model like _GLM-4.5_.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you are having trouble with configuring a provider, check the following:
|
||||
|
||||
@@ -71,7 +71,7 @@ const ogImage = `${config.socialCard}/opencode-share/${encodedTitle}.png?model=$
|
||||
tag: "meta",
|
||||
attrs: {
|
||||
name: "robots",
|
||||
content: "noindex, nofollow, noarchive, nosnippet",
|
||||
content: "noindex",
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
diff --git a/node_modules/marked-shiki/.bun-tag-5eae3435af8a0229 b/.bun-tag-5eae3435af8a0229
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
||||
diff --git a/dist/index.js b/dist/index.js
|
||||
index 535885e8569626d08f205e76c4944e4ebd0decab..92b5695c1b05fc7db5d26128c8f948d43c91f88a 100644
|
||||
--- a/dist/index.js
|
||||
+++ b/dist/index.js
|
||||
@@ -4,7 +4,7 @@ function o(s = {}) {
|
||||
async: !0,
|
||||
async walkTokens(t) {
|
||||
if (t.type !== "code" || typeof e != "function") return;
|
||||
- const [a = "text", ...i] = t.lang.split(" "), { text: c } = t, r = await e(c, a, i), l = n ? n.replace("%l", String(a).toUpperCase()).replace("%s", r).replace("%t", c) : r;
|
||||
+ const [a = "text", ...i] = t.lang?.split(" "), { text: c } = t, r = await e(c, a, i), l = n ? n.replace("%l", String(a).toUpperCase()).replace("%s", r).replace("%t", c) : r;
|
||||
Object.assign(t, {
|
||||
type: "html",
|
||||
block: !0,
|
||||
+8
-27
@@ -2,8 +2,6 @@
|
||||
|
||||
import { $ } from "bun"
|
||||
|
||||
console.log("=== publishing ===\n")
|
||||
|
||||
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
|
||||
const version = snapshot
|
||||
? `0.0.0-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
|
||||
@@ -12,45 +10,28 @@ if (!version) {
|
||||
throw new Error("OPENCODE_VERSION is required")
|
||||
}
|
||||
process.env["OPENCODE_VERSION"] = version
|
||||
console.log("version:", version)
|
||||
|
||||
const pkgjsons = await Array.fromAsync(
|
||||
new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
}),
|
||||
).then((arr) => arr.filter((x) => !x.includes("node_modules") && !x.includes("dist")))
|
||||
|
||||
const tree = await $`git add . && git write-tree`.text().then((x) => x.trim())
|
||||
for (const file of pkgjsons) {
|
||||
for await (const file of new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
})) {
|
||||
let pkg = await Bun.file(file).text()
|
||||
pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${version}"`)
|
||||
console.log("updated:", file)
|
||||
await Bun.file(file).write(pkg)
|
||||
}
|
||||
await $`bun install`
|
||||
|
||||
console.log("\n=== opencode ===\n")
|
||||
await import(`../packages/opencode/script/publish.ts`)
|
||||
|
||||
console.log("\n=== sdk ===\n")
|
||||
// await import(`../packages/opencode/script/publish.ts`)
|
||||
await import(`../packages/sdk/js/script/publish.ts`)
|
||||
|
||||
console.log("\n=== plugin ===\n")
|
||||
await import(`../packages/plugin/script/publish.ts`)
|
||||
// await import(`../packages/sdk/stainless/generate.ts`)
|
||||
|
||||
if (!snapshot) {
|
||||
await $`git commit -am "release: v${version}"`
|
||||
await $`git tag v${version}`
|
||||
await $`git push origin HEAD --tags --no-verify`
|
||||
await $`git push origin HEAD --tags`
|
||||
}
|
||||
if (snapshot) {
|
||||
await $`git checkout -b snapshot-${version}`
|
||||
await $`git commit --allow-empty -m "Snapshot release v${version}"`
|
||||
await $`git tag v${version}`
|
||||
await $`git push origin v${version} --no-verify`
|
||||
await $`git checkout dev`
|
||||
await $`git branch -D snapshot-${version}`
|
||||
for (const file of pkgjsons) {
|
||||
await $`git checkout ${tree} ${file}`
|
||||
}
|
||||
await $`git push origin v${version}`
|
||||
await $`git reset --soft HEAD~1`
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "0.3.129",
|
||||
"version": "0.0.0-202508022053",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import * as assert from 'assert';
|
||||
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
import * as vscode from 'vscode';
|
||||
// import * as myExtension from '../../extension';
|
||||
|
||||
suite('Extension Test Suite', () => {
|
||||
vscode.window.showInformationMessage('Start all tests.');
|
||||
|
||||
test('Sample test', () => {
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});
|
||||
Vendored
-20
@@ -5,10 +5,6 @@
|
||||
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"ANTHROPIC_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"Api": {
|
||||
"type": "sst.cloudflare.Worker"
|
||||
"url": string
|
||||
@@ -24,26 +20,10 @@ declare module "sst" {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"GatewayApi": {
|
||||
"type": "sst.cloudflare.Worker"
|
||||
"url": string
|
||||
}
|
||||
"OPENAI_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"OPENCODE_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"Web": {
|
||||
"type": "sst.cloudflare.Astro"
|
||||
"url": string
|
||||
}
|
||||
"ZHIPU_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <reference path="sst-env.d.ts" />
|
||||
|
||||
+1
-2
@@ -10,10 +10,9 @@ export default $config({
|
||||
}
|
||||
},
|
||||
async run() {
|
||||
const { api, gateway } = await import("./infra/app.js")
|
||||
const { api } = await import("./infra/app.js")
|
||||
return {
|
||||
api: api.url,
|
||||
gateway: gateway.url,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user