Compare commits

...

48 Commits

Author SHA1 Message Date
opencode
4954edf8ae release: v0.9.0 2025-09-15 07:18:49 +00:00
Dax
c1b4e1f19d Upgrade to Zod v4 (#2605)
Co-authored-by: GitHub Action <action@github.com>
2025-09-15 03:12:07 -04:00
Aiden Cline
89d820b1c4 fix: visual token bug (#2603) 2025-09-14 21:23:52 -05:00
Aiden Cline
e3e459fc50 fix: reasoning metadata persistence (#2602) 2025-09-14 16:28:06 -05:00
Tommy D. Rossi
4bf0541bd6 log bash output when using opencode run (#2595) 2025-09-14 09:03:40 -05:00
Aiden Cline
c81624aef7 tweak: make bash permissions key off of command pattern (#2592) 2025-09-14 09:01:57 -05:00
Kenn Costales
df61aa801b fix: fix wrong tool references LS and Agent (#2466) 2025-09-14 08:53:50 -05:00
GitHub Action
6af0c2ec21 ignore: update download stats 2025-09-14 2025-09-14 12:03:54 +00:00
Dax Raad
ce9d2ee04f ci: script 2025-09-14 02:07:58 -04:00
opencode
4b30705c42 release: v0.8.0 2025-09-14 06:07:43 +00:00
Mani Sundararajan
1f8d396b76 fix(dev): build tui with correct file ext for windows (#2590) 2025-09-14 01:59:25 -04:00
Aiden Cline
3752bb9717 fix: token counting visual bug (#2587) 2025-09-13 19:46:24 -05:00
Aiden Cline
16d66c209d respect subagent in command, add subtask flag (#2569) 2025-09-13 12:47:18 -05:00
Aiden Cline
6506e48c54 tweak: keep aborted msgs in context (#2583) 2025-09-13 12:25:30 -05:00
GitHub Action
f0e8b7c29b ignore: update download stats 2025-09-13 2025-09-13 12:03:56 +00:00
Dax Raad
a00b49d65b disable autocompact if context is 0 2025-09-13 05:59:18 -04:00
Dax Raad
b1589be4ba add disable OPENCODE_DISABLE_AUTOCOMPACT 2025-09-13 05:55:04 -04:00
Dax Raad
eb24d2f847 ignore: fix 2025-09-13 05:53:03 -04:00
Dax
9bb25a9260 Session management and prompt handling improvements (#2577)
Co-authored-by: GitHub Action <action@github.com>
2025-09-13 05:46:14 -04:00
opencode
535230dce4 release: v0.7.9 2025-09-13 05:29:37 +00:00
Dax Raad
555fb53505 nudge llm to continue properly after compaction 2025-09-13 01:23:54 -04:00
Tommy D. Rossi
b1e0a23351 fix: ShellError: exit code 1 errors (#2568)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-13 00:06:07 -05:00
Nicholas Hamilton
2b69bcccdf docs: typo in web agents.mdx (#2574) 2025-09-12 23:26:52 -05:00
Trillium Smith
e03f27381f docs: add tip block for finding available models (#2501)
Co-authored-by: GitHub Action <action@github.com>
2025-09-12 21:22:54 -04:00
Aiden Cline
aebd50da7e fix: make permission always behavior match expectation (#2573) 2025-09-12 18:59:38 -05:00
Stephen Murray
c02f58c2af fix: await cleanupRevert() to prevent dupe msgs after undo (#2572) 2025-09-12 18:42:39 -05:00
Dax Raad
c8f4d54f7f wip: zen 2025-09-12 14:53:00 -04:00
GitHub Action
4983d255dd chore: format code 2025-09-12 18:46:43 +00:00
Dax Raad
f2b4891ff0 wip: zen 2025-09-12 14:46:08 -04:00
GitHub Action
efcb5abbf7 chore: format code 2025-09-12 18:33:14 +00:00
Jay V
d37e58719e ignore: zen 2025-09-12 14:32:43 -04:00
Frank
c6c153de95 wip: zen 2025-09-12 14:22:42 -04:00
opencode
417e8f619c release: v0.7.8 2025-09-12 18:09:55 +00:00
Dax Raad
f2094b7bb3 temporarily disable midstream compaction 2025-09-12 14:00:54 -04:00
Dax Raad
176dc51b2e ci: exclude production branch from format workflow 2025-09-12 13:41:38 -04:00
opencode
f7d9a031e6 release: v0.7.7 2025-09-12 17:28:35 +00:00
Dax Raad
3e2478ebf9 undo session pruning 2025-09-12 13:20:13 -04:00
GitHub Action
1f4e8b4954 chore: format code 2025-09-12 16:19:09 +00:00
Frank
9a346a00fb wip: zen 2025-09-12 12:18:32 -04:00
Frank
0a13820927 Merge branch 'production' into dev 2025-09-12 12:04:27 -04:00
GitHub Action
c5fa3ee9f8 chore: format code 2025-09-12 15:57:50 +00:00
Frank
c294a18155 wip: zen 2025-09-12 11:57:14 -04:00
Frank
c3dc6d6df6 wip: zen 2025-09-12 11:57:14 -04:00
GitHub Action
ef3425a177 ignore: update download stats 2025-09-12 2025-09-12 12:04:14 +00:00
Dax Raad
0290b4aaf0 ignore: internal 2025-09-12 10:45:44 +00:00
opencode
4ceee53480 release: v0.7.6 2025-09-12 10:45:44 +00:00
Dax Raad
469dc9095f add microcompact 2025-09-12 06:38:47 -04:00
GitHub Action
1bd198eb34 chore: format code 2025-09-11 22:34:21 +00:00
113 changed files with 5108 additions and 3141 deletions

View File

@@ -2,7 +2,11 @@ name: Format
on:
push:
branches-ignore:
- production
pull_request:
branches-ignore:
- production
workflow_dispatch:
jobs:
format:

View File

@@ -76,3 +76,6 @@
| 2025-09-09 | 300,036 (+6,695) | 229,788 (+2,715) | 529,824 (+9,410) |
| 2025-09-10 | 307,287 (+7,251) | 233,435 (+3,647) | 540,722 (+10,898) |
| 2025-09-11 | 314,083 (+6,796) | 237,356 (+3,921) | 551,439 (+10,717) |
| 2025-09-12 | 321,046 (+6,963) | 240,728 (+3,372) | 561,774 (+10,335) |
| 2025-09-13 | 324,894 (+3,848) | 245,539 (+4,811) | 570,433 (+8,659) |
| 2025-09-14 | 328,876 (+3,982) | 248,245 (+2,706) | 577,121 (+6,688) |

View File

@@ -7,8 +7,8 @@
"pulumi-stripe": "0.0.24",
},
"devDependencies": {
"prettier": "3.5.3",
"sst": "3.17.12",
"prettier": "3.6.2",
"sst": "3.17.13",
},
},
"cloud/app": {
@@ -26,7 +26,7 @@
},
"cloud/core": {
"name": "@opencode/cloud-core",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@opencode/cloud-resource": "workspace:*",
@@ -43,7 +43,7 @@
},
"cloud/function": {
"name": "@opencode/cloud-function",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -69,7 +69,7 @@
},
"cloud/scripts": {
"name": "@opencode/cloud-scripts",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@opencode/cloud-core": "workspace:*",
"tsx": "4.20.5",
@@ -81,7 +81,7 @@
},
"packages/function": {
"name": "@opencode/function",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "22.0.0",
@@ -96,12 +96,13 @@
},
"packages/opencode": {
"name": "opencode",
"version": "0.6.10",
"version": "0.8.0",
"bin": {
"opencode": "./bin/opencode",
},
"dependencies": {
"@clack/prompts": "1.0.0-alpha.1",
"@hono/standard-validator": "0.1.5",
"@hono/zod-validator": "catalog:",
"@modelcontextprotocol/sdk": "1.15.1",
"@openauthjs/openauth": "0.4.3",
@@ -114,7 +115,7 @@
"diff": "8.0.2",
"gray-matter": "4.0.3",
"hono": "catalog:",
"hono-openapi": "0.4.8",
"hono-openapi": "1.0.7",
"ignore": "7.0.5",
"jsonc-parser": "3.3.1",
"minimatch": "10.0.3",
@@ -129,7 +130,6 @@
"xdg-basedir": "5.1.0",
"yargs": "18.0.0",
"zod": "catalog:",
"zod-openapi": "4.1.0",
},
"devDependencies": {
"@ai-sdk/amazon-bedrock": "2.2.10",
@@ -146,7 +146,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
},
@@ -157,7 +157,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@hey-api/openapi-ts": "0.81.0",
},
@@ -169,7 +169,7 @@
},
"packages/web": {
"name": "@opencode/web",
"version": "0.6.10",
"version": "0.8.0",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -212,7 +212,7 @@
"@solidjs/start@1.1.7": "patches/@solidjs%2Fstart@1.1.7.patch",
},
"overrides": {
"zod": "3.25.76",
"zod": "4.1.8",
},
"catalog": {
"@hono/zod-validator": "0.4.2",
@@ -224,7 +224,7 @@
"remeda": "2.26.0",
"solid-js": "1.9.9",
"typescript": "5.8.2",
"zod": "3.25.76",
"zod": "4.1.8",
},
"packages": {
"@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=="],
@@ -243,8 +243,6 @@
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
"@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@11.9.3", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ=="],
"@astrojs/cloudflare": ["@astrojs/cloudflare@12.6.3", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.1", "@astrojs/underscore-redirects": "1.0.0", "@cloudflare/workers-types": "^4.20250507.0", "tinyglobby": "^0.2.13", "vite": "^6.3.5", "wrangler": "^4.14.1" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-xhJptF5tU2k5eo70nIMyL1Udma0CqmUEnGSlGyFflLqSY82CRQI6nWZ/xZt0ZvmXuErUjIx0YYQNfZsz5CNjLQ=="],
"@astrojs/compiler": ["@astrojs/compiler@2.12.2", "", {}, "sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw=="],
@@ -495,6 +493,8 @@
"@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.81.0", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "js-yaml": "4.1.0", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-PoJukNBkUfHOoMDpN33bBETX49TUhy7Hu8Sa0jslOvFndvZ5VjQr4Nl/Dzjb9LG1Lp5HjybyTJMA6a1zYk/q6A=="],
"@hono/standard-validator": ["@hono/standard-validator@0.1.5", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-EIyZPPwkyLn6XKwFj5NBEWHXhXbgmnVh2ceIFo5GO7gKI9WmzTjPDKnppQB0KrqKeAkq3kpoW4SIbu5X1dgx3w=="],
"@hono/zod-validator": ["@hono/zod-validator@0.4.2", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-1rrlBg+EpDPhzOV4hT9pxr5+xDVmKuz6YJl+la7VCwK6ass5ldyKm5fD+umJdV2zhHD6jROoCCv8NbTwyfhT0g=="],
"@ibm/plex": ["@ibm/plex@6.4.1", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.1" } }, "sha512-fnsipQywHt3zWvsnlyYKMikcVI7E2fEwpiPnIHFqlbByXVfQfANAAeJk1IV4mNnxhppUIDlhU0TzwYwL++Rn2g=="],
@@ -973,6 +973,10 @@
"@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="],
"@standard-community/standard-json": ["@standard-community/standard-json@0.3.1", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "valibot", "zod", "zod-to-json-schema"] }, "sha512-QYW1sZWWheij2CZnUL8LAFK5oECJe7cQUqtao1dY4Pjp/RPidOmpgS4L3pm9rR2gzFoyjpS5Q0MhF3c0Bxzevg=="],
"@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.4", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.1", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "openapi-types": "^12.1.3", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "valibot", "zod", "zod-openapi"] }, "sha512-guPU+9Y+Y9JN0gpBQbZMlIYzRSaRyTe7f+g6JCV3d0rrMQ5JFngLQKRyg3MP07xIts8nGim167Y9ePfdlkJp0Q=="],
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="],
@@ -1759,7 +1763,7 @@
"hono": ["hono@4.7.10", "", {}, "sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ=="],
"hono-openapi": ["hono-openapi@0.4.8", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "valibot", "zod", "zod-openapi"] }, "sha512-LYr5xdtD49M7hEAduV1PftOMzuT8ZNvkyWfh1DThkLsIr4RkvDb12UxgIiFbwrJB6FLtFXLoOZL9x4IeDk2+VA=="],
"hono-openapi": ["hono-openapi@1.0.7", "", { "peerDependencies": { "@hono/standard-validator": "^0.1.2", "@standard-community/standard-json": "^0.3.1", "@standard-community/standard-openapi": "^0.2.4", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-rMn+nn4/HMisyi549L3zT7WCmVvmpiKsyt790GcGfqvJf9mJfhq6txw09l0IhSBxpJpA0pXVKxFijcsnGfshUA=="],
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
@@ -1919,8 +1923,6 @@
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-schema-walker": ["json-schema-walker@2.0.0", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.1.0", "clone": "^2.1.2" } }, "sha512-nXN2cMky0Iw7Af28w061hmxaPDaML5/bQD9nwm1lOoIKEGjHcRGxqWe4MfrkYThYAPjSUhmsp4bJNoLAyVn9Xw=="],
"json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="],
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
@@ -2365,7 +2367,7 @@
"precinct": ["precinct@12.2.0", "", { "dependencies": { "@dependents/detective-less": "^5.0.1", "commander": "^12.1.0", "detective-amd": "^6.0.1", "detective-cjs": "^6.0.1", "detective-es6": "^5.0.1", "detective-postcss": "^7.0.1", "detective-sass": "^6.0.1", "detective-scss": "^5.0.1", "detective-stylus": "^5.0.1", "detective-typescript": "^14.0.0", "detective-vue2": "^2.2.0", "module-definition": "^6.0.1", "node-source-walk": "^7.0.1", "postcss": "^8.5.1", "typescript": "^5.7.3" }, "bin": { "precinct": "bin/cli.js" } }, "sha512-NFBMuwIfaJ4SocE9YXPU/n4AcNSoFMVFjP72nvl3cx69j/ke61/hPOWFREVxLkFhhEGnA8ZuVfTqJBa+PK3b5w=="],
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="],
@@ -2647,23 +2649,23 @@
"ssri": ["ssri@10.0.6", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ=="],
"sst": ["sst@3.17.12", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.12", "sst-darwin-x64": "3.17.12", "sst-linux-arm64": "3.17.12", "sst-linux-x64": "3.17.12", "sst-linux-x86": "3.17.12", "sst-win32-arm64": "3.17.12", "sst-win32-x64": "3.17.12", "sst-win32-x86": "3.17.12" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-UwUbucNZRLp9GHgPAwkat1sBsNGaJfHsLXZHCMKsolCW7CEuugJfvBl2vOyJrhKP4N+Xnv1QFh0BGsOmN0kQeA=="],
"sst": ["sst@3.17.13", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.13", "sst-darwin-x64": "3.17.13", "sst-linux-arm64": "3.17.13", "sst-linux-x64": "3.17.13", "sst-linux-x86": "3.17.13", "sst-win32-arm64": "3.17.13", "sst-win32-x64": "3.17.13", "sst-win32-x86": "3.17.13" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-NaNTZL7uk2AsXzPBySQy7aqXlStXorR+bA785NxvCbskwkc44nVSQcEsvX5tdsD6/jrWpw9tDy4sStv2ycLAng=="],
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9Oky2ZmJoeEN97ALWtFRt3kvSIZLjYoQoOtJvTaNQJTFi/9OsUE/6I5zdedf5GhMKCT1JvY+Ngpv3U3Y6SEYOg=="],
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZaDReT/c+2CcEnFkYjMty63II2ckQrUniiSdoEH6eAWyU1Iy7UwKK4I2GYm+5dy9xeSBaOKga6FMdLqFxIiUg=="],
"sst-darwin-x64": ["sst-darwin-x64@3.17.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-n6tWCjFF9Pb+QzxXJmuTGfQ4GW96Nf6ATtb7Wpa+9RDLRHrEBdOjXAp7osr7MB9djPRkt4942nwUZ7wX/EULpg=="],
"sst-darwin-x64": ["sst-darwin-x64@3.17.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-1DlYMrmrI5RY3/Ob039JatgvDKZ5QNtyRkVu0WcnsOvcxFE4dzrCiYKYHg2A+FMDl+H1qcwy2gGA3BTwC9in1w=="],
"sst-linux-arm64": ["sst-linux-arm64@3.17.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-iMflBzQWhF5kmRdXu402dwVpQI9LfFR3yFok3HUTV0ema5Pq2kPphEatEEw1dyG2ZXCBLeKN+T3Ujjfer+ddRA=="],
"sst-linux-arm64": ["sst-linux-arm64@3.17.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-A4+ZamchUdaX0pqvYWZ+r7OP1bruwEj9qgWT5kU7Q5pqaotIsEitYQi0q9nZFKH+5mXYesUwSy5FA+Q8T3X/Rg=="],
"sst-linux-x64": ["sst-linux-x64@3.17.12", "", { "os": "linux", "cpu": "x64" }, "sha512-89rZXs3IfGrY9yiDNuLfcJvHnAUX1gRVeB+lqQ1M2sbJD2iMpN+fx93owcApAndtZYzYNfQYEZ/xYwI6HFfu4w=="],
"sst-linux-x64": ["sst-linux-x64@3.17.13", "", { "os": "linux", "cpu": "x64" }, "sha512-yhKZc5CojqjB2DnyeVka5jeRb4oc3lBx8Qf6or0w4cs47SBIqyvO0iR/3IeKvRRL1hiEUeUF8r/q83rQo9jZMw=="],
"sst-linux-x86": ["sst-linux-x86@3.17.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zc2nd2syaq/DfNxtDcn4NOh8RBCaCZ1qsjLFpvGGfMMRnGiWjofuE6eFX3fhchGL3uvaqwlENvtzj4UC/MF5wQ=="],
"sst-linux-x86": ["sst-linux-x86@3.17.13", "", { "os": "linux", "cpu": "none" }, "sha512-G1FIUmpUaECB/3CV5EO/y1QmV5mQ8RUkFeZq64oyILEEaMzSWWKz0glHzQ3+p316VE74MzbktiWRqsCKQy8GeA=="],
"sst-win32-arm64": ["sst-win32-arm64@3.17.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-Bb7M6PoImmGeyzJu75QbNHBs0mDp21DsKFyMucn2dwxYwahuFPjjMbG+tlziWtxcNgdZMdEcy9jR8ot1jAIh0Q=="],
"sst-win32-arm64": ["sst-win32-arm64@3.17.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-9uCiIXmsGoxGeNWgM81x/d6V/vecjoiHXhBUPDGlQ1Dct1SbtHAgaf/g2ec5XwSQb9B/tne4qk81eMlTl83Z1A=="],
"sst-win32-x64": ["sst-win32-x64@3.17.12", "", { "os": "win32", "cpu": "x64" }, "sha512-7f41o1WhxdcuLhHijoavkX5O3L/Pnma6zCoL3kG6f9Njc6Zyj8Oha2fQz6Tesb/Qt8deG04WU4bL3FmxgNHU6g=="],
"sst-win32-x64": ["sst-win32-x64@3.17.13", "", { "os": "win32", "cpu": "x64" }, "sha512-hTuj4rFSCI/9tX4NMUpNJ69Q9td/giekELDRNv03ys8TpJGoGvPT8D6VD1eX7j1CQnOZIgeEphfW9WmCXkLaIA=="],
"sst-win32-x86": ["sst-win32-x86@3.17.12", "", { "os": "win32", "cpu": "none" }, "sha512-AfsNJQMTlefHitaVRWh5Uf3AaICIaomFbSo5qDbibgkvhbppCxgMFpW0IxiWySjWrCN5hMMkxdxlZP9IHqqxjQ=="],
"sst-win32-x86": ["sst-win32-x86@3.17.13", "", { "os": "win32", "cpu": "none" }, "sha512-AuMDGux+H1kPckKJ7Szgi04EpBoOKh/v5zFNAPjvWSkcWcGZ+hsBUx3h/FO/AkGK3RnlLMRj4CQQLoa10RSSIg=="],
"stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="],
@@ -2977,7 +2979,7 @@
"zip-stream": ["zip-stream@6.0.1", "", { "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", "readable-stream": "^4.0.0" } }, "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
"zod-openapi": ["zod-openapi@4.1.0", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-bRCwRYhEO9CmFLyKgJX8h6j1dRtRiwOe+TLzMVPyV0pRW5vRIgb1rLgIGcuRZ5z3MmSVrZqbv3yva4IJrtZK4g=="],

View File

@@ -7,7 +7,7 @@
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build && ../../packages/opencode/script/schema.ts ./.output/public/config.json",
"start": "vinxi start",
"version": "0.7.5"
"version": "0.9.0"
},
"dependencies": {
"@ibm/plex": "6.4.1",

View File

@@ -115,11 +115,18 @@
[data-component="api-keys-section"] {
[data-slot="create-form"] {
display: flex;
flex-direction: column;
gap: var(--space-3);
padding: var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
[data-slot="input-container"] {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
@media (max-width: 30rem) {
gap: var(--space-2);
}
@@ -148,6 +155,13 @@
display: flex;
gap: var(--space-2);
}
[data-slot="form-error"] {
color: var(--color-danger);
font-size: var(--font-size-sm);
margin-top: var(--space-1);
line-height: 1.4;
}
}
[data-slot="api-keys-table"] {
@@ -453,10 +467,15 @@
[data-slot="new-user-sections"] {
display: flex;
flex-direction: column;
gap: var(--space-16);
gap: var(--space-8);
padding: var(--space-6);
background-color: var(--color-bg-surface);
border: 1px dashed var(--color-border);
border-radius: var(--border-radius-sm);
@media (max-width: 30rem) {
gap: var(--space-8);
padding: var(--space-4);
}
[data-component="feature-grid"] {
@@ -476,7 +495,6 @@
padding: var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
background-color: var(--color-bg-surface);
h3 {
font-size: var(--font-size-sm);
@@ -532,7 +550,6 @@
padding: var(--space-4);
border: 2px solid var(--color-accent);
border-radius: var(--border-radius-sm);
background-color: var(--color-bg-surface);
align-items: center;
@media (max-width: 40rem) {
@@ -585,26 +602,6 @@
flex-direction: column;
gap: var(--space-6);
[data-slot="section-title"] {
display: flex;
flex-direction: column;
gap: var(--space-1);
h2 {
font-size: var(--font-size-md);
font-weight: 600;
line-height: 1.2;
letter-spacing: -0.03125rem;
margin: 0;
color: var(--color-text-secondary);
text-transform: uppercase;
@media (max-width: 30rem) {
font-size: var(--font-size-md);
}
}
}
ol {
margin: 0;
padding-left: 0;
@@ -614,15 +611,14 @@
list-style-position: inside;
li {
font-size: var(--font-size-sm);
font-size: var(--font-size-md);
line-height: 1.5;
color: var(--color-text-muted);
color: var(--color-text-secondary);
code {
font-family: var(--font-mono);
font-size: var(--font-size-xs);
font-size: var(--font-size-sm);
padding: var(--space-1) var(--space-2);
background-color: var(--color-bg-surface);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
color: var(--color-text);

View File

@@ -49,7 +49,13 @@ const createKey = action(async (form: FormData) => {
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(
withActor(() => Key.create({ name }), workspaceID),
await withActor(
() =>
Key.create({ name })
.then((data) => ({ error: undefined, data }))
.catch((e) => ({ error: e.message as string })),
workspaceID,
),
{ revalidate: listKeys.key },
)
}, "key.create")
@@ -60,10 +66,7 @@ const removeKey = action(async (form: FormData) => {
if (!id) return { error: "ID is required" }
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(
withActor(() => Key.remove({ id }), workspaceID),
{ revalidate: listKeys.key },
)
return json(await withActor(() => Key.remove({ id }), workspaceID), { revalidate: listKeys.key })
}, "key.remove")
/////////////////////////////////////
@@ -185,19 +188,26 @@ function KeySection() {
function KeyCreateForm() {
const params = useParams()
const submission = useSubmission(createKey)
const [store, setStore] = createStore({
show: false,
})
const [store, setStore] = createStore({ show: false })
let input: HTMLInputElement
createEffect(() => {
if (!submission.pending && submission.result) {
if (!submission.pending && submission.result && !submission.result.error) {
hide()
}
})
function show() {
// submission.clear() does not clear the result in some cases, ie.
// 1. Create key with empty name => error shows
// 2. Put in a key name and creates the key => form hides
// 3. Click add key button again => form shows with the same error if
// submission.clear() is called only once
while (true) {
submission.clear()
if (!submission.result) break
}
setStore("show", true)
input.focus()
}
@@ -216,7 +226,12 @@ function KeyCreateForm() {
}
>
<form action={createKey} method="post" data-slot="create-form">
<input ref={(r) => (input = r)} data-component="input" name="name" type="text" placeholder="Enter key name" />
<div data-slot="input-container">
<input ref={(r) => (input = r)} data-component="input" name="name" type="text" placeholder="Enter key name" />
<Show when={submission.result && submission.result.error}>
{(err) => <div data-slot="form-error">{err()}</div>}
</Show>
</div>
<input type="hidden" name="workspaceID" value={params.id} />
<div data-slot="form-actions">
<button type="reset" data-color="ghost" onClick={() => hide()}>
@@ -406,10 +421,6 @@ function NewUserSection() {
</div>
<div data-component="api-key-highlight">
<div data-slot="section-title">
<h2>Your API Key</h2>
</div>
<Show when={defaultKey()}>
<div data-slot="key-display">
<div data-slot="key-container">
@@ -441,15 +452,12 @@ function NewUserSection() {
</div>
<div data-component="next-steps">
<div data-slot="section-title">
<h2>Next Steps</h2>
</div>
<ol>
<li>Copy your API key above</li>
<li>
Run <code>opencode auth login</code> and select opencode
</li>
<li>Paste your API key when prompted</li>
<li>Paste your API key</li>
<li>Start opencode</li>
<li>
Run <code>/models</code> to see available models
</li>

View File

@@ -1,8 +1,26 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/util/zen"
type Usage = {
prompt_tokens?: number
completion_tokens?: number
total_tokens?: number
prompt_tokens_details?: {
text_tokens?: number
audio_tokens?: number
image_tokens?: number
cached_tokens?: number
}
completion_tokens_details?: {
reasoning_tokens?: number
audio_tokens?: number
accepted_prediction_tokens?: number
rejected_prediction_tokens?: number
}
}
export function POST(input: APIEvent) {
let usage: any
let usage: Usage
return handler(input, {
modifyBody: (body: any) => ({
...body,
@@ -17,7 +35,7 @@ export function POST(input: APIEvent) {
let json
try {
json = JSON.parse(chunk.slice(6))
json = JSON.parse(chunk.slice(6)) as { usage?: Usage }
} catch (e) {
return
}
@@ -26,11 +44,11 @@ export function POST(input: APIEvent) {
usage = json.usage
},
getStreamUsage: () => usage,
normalizeUsage: (usage: any) => ({
normalizeUsage: (usage: Usage) => ({
inputTokens: usage.prompt_tokens ?? 0,
outputTokens: usage.completion_tokens ?? 0,
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? 0,
cacheReadTokens: usage.prompt_tokens_details?.cached_tokens ?? 0,
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? undefined,
cacheReadTokens: usage.prompt_tokens_details?.cached_tokens ?? undefined,
}),
})
}

View File

@@ -53,9 +53,9 @@ export function POST(input: APIEvent) {
normalizeUsage: (usage: Usage) => ({
inputTokens: usage.input_tokens ?? 0,
outputTokens: usage.output_tokens ?? 0,
cacheReadTokens: usage.cache_read_input_tokens ?? 0,
cacheWrite5mTokens: usage.cache_creation?.ephemeral_5m_input_tokens,
cacheWrite1hTokens: usage.cache_creation?.ephemeral_1h_input_tokens,
cacheReadTokens: usage.cache_read_input_tokens ?? undefined,
cacheWrite5mTokens: usage.cache_creation?.ephemeral_5m_input_tokens ?? undefined,
cacheWrite1hTokens: usage.cache_creation?.ephemeral_1h_input_tokens ?? undefined,
}),
})
}

View File

@@ -1,8 +1,20 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/util/zen"
type Usage = {
input_tokens?: number
input_tokens_details?: {
cached_tokens?: number
}
output_tokens?: number
output_tokens_details?: {
reasoning_tokens?: number
}
total_tokens?: number
}
export function POST(input: APIEvent) {
let usage: any
let usage: Usage
return handler(input, {
setAuthHeader: (headers: Headers, apiKey: string) => {
headers.set("authorization", `Bearer ${apiKey}`)
@@ -15,7 +27,7 @@ export function POST(input: APIEvent) {
let json
try {
json = JSON.parse(data.slice(6))
json = JSON.parse(data.slice(6)) as { response?: { usage?: Usage } }
} catch (e) {
return
}
@@ -24,14 +36,14 @@ export function POST(input: APIEvent) {
usage = json.response.usage
},
getStreamUsage: () => usage,
normalizeUsage: (usage: any) => {
normalizeUsage: (usage: Usage) => {
const inputTokens = usage.input_tokens ?? 0
const outputTokens = usage.output_tokens ?? 0
const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0
const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? 0
const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? undefined
const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? undefined
return {
inputTokens: inputTokens - cacheReadTokens,
outputTokens: outputTokens - reasoningTokens,
inputTokens: inputTokens - (cacheReadTokens ?? 0),
outputTokens: outputTokens - (reasoningTokens ?? 0),
reasoningTokens,
cacheReadTokens,
}

View File

@@ -10,10 +10,11 @@ import { Resource } from "@opencode/cloud-resource"
type ModelCost = {
input: number
output: number
cacheRead: number
cacheWrite5m: number
cacheWrite1h: number
cacheRead?: number
cacheWrite5m?: number
cacheWrite1h?: number
}
type Model = {
id: string
auth: boolean
@@ -42,7 +43,7 @@ export async function handler(
inputTokens: number
outputTokens: number
reasoningTokens?: number
cacheReadTokens: number
cacheReadTokens?: number
cacheWrite5mTokens?: number
cacheWrite1hTokens?: number
}
@@ -129,8 +130,6 @@ export async function handler(
input: 0.00000125,
output: 0.00001,
cacheRead: 0.000000125,
cacheWrite5m: 0,
cacheWrite1h: 0,
},
headerMappings: {},
providers: {
@@ -147,9 +146,6 @@ export async function handler(
cost: {
input: 0.00000045,
output: 0.0000018,
cacheRead: 0,
cacheWrite5m: 0,
cacheWrite1h: 0,
},
headerMappings: {},
providers: {
@@ -173,9 +169,6 @@ export async function handler(
cost: {
input: 0.0000006,
output: 0.0000025,
cacheRead: 0,
cacheWrite5m: 0,
cacheWrite1h: 0,
},
headerMappings: {},
providers: {
@@ -200,8 +193,6 @@ export async function handler(
input: 0,
output: 0,
cacheRead: 0,
cacheWrite5m: 0,
cacheWrite1h: 0,
},
headerMappings: {
"x-grok-conv-id": "x-opencode-session",
@@ -222,9 +213,6 @@ export async function handler(
cost: {
input: 0.00000038,
output: 0.00000153,
cacheRead: 0,
cacheWrite5m: 0,
cacheWrite1h: 0,
},
headerMappings: {},
providers: {
@@ -438,15 +426,30 @@ export async function handler(
const inputCost = modelCost.input * inputTokens * 100
const outputCost = modelCost.output * outputTokens * 100
const reasoningCost = reasoningTokens ? modelCost.output * reasoningTokens * 100 : undefined
const cacheReadCost = modelCost.cacheRead * cacheReadTokens * 100
const cacheWrite5mCost = cacheWrite5mTokens ? modelCost.cacheWrite5m * cacheWrite5mTokens * 100 : undefined
const cacheWrite1hCost = cacheWrite1hTokens ? modelCost.cacheWrite1h * cacheWrite1hTokens * 100 : undefined
const reasoningCost = (() => {
if (!reasoningTokens) return undefined
return modelCost.output * reasoningTokens * 100
})()
const cacheReadCost = (() => {
if (!cacheReadTokens) return undefined
if (!modelCost.cacheRead) return undefined
return modelCost.cacheRead * cacheReadTokens * 100
})()
const cacheWrite5mCost = (() => {
if (!cacheWrite5mTokens) return undefined
if (!modelCost.cacheWrite5m) return undefined
return modelCost.cacheWrite5m * cacheWrite5mTokens * 100
})()
const cacheWrite1hCost = (() => {
if (!cacheWrite1hTokens) return undefined
if (!modelCost.cacheWrite1h) return undefined
return modelCost.cacheWrite1h * cacheWrite1hTokens * 100
})()
const totalCostInCent =
inputCost +
outputCost +
(reasoningCost ?? 0) +
cacheReadCost +
(cacheReadCost ?? 0) +
(cacheWrite5mCost ?? 0) +
(cacheWrite1hCost ?? 0)
@@ -460,7 +463,7 @@ export async function handler(
"cost.input": Math.round(inputCost),
"cost.output": Math.round(outputCost),
"cost.reasoning": reasoningCost ? Math.round(reasoningCost) : undefined,
"cost.cache_read": Math.round(cacheReadCost),
"cost.cache_read": cacheReadCost ? Math.round(cacheReadCost) : undefined,
"cost.cache_write_5m": cacheWrite5mCost ? Math.round(cacheWrite5mCost) : undefined,
"cost.cache_write_1h": cacheWrite1hCost ? Math.round(cacheWrite1hCost) : undefined,
"cost.total": Math.round(totalCostInCent),
@@ -479,7 +482,8 @@ export async function handler(
outputTokens,
reasoningTokens,
cacheReadTokens,
cacheWriteTokens: (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0),
cacheWrite5mTokens,
cacheWrite1hTokens,
cost,
})
await tx

View File

@@ -0,0 +1 @@
ALTER TABLE `usage` MODIFY COLUMN `provider` varchar(255) NOT NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE `usage` ADD `cache_write_5m_tokens` int;--> statement-breakpoint
ALTER TABLE `usage` ADD `cache_write_1h_tokens` int;

View File

@@ -0,0 +1 @@
ALTER TABLE `usage` DROP COLUMN `cache_write_tokens`;

View File

@@ -0,0 +1,588 @@
{
"version": "5",
"dialect": "mysql",
"id": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff",
"prevId": "06dc6226-bfbb-4ccc-b4bc-f26070c3bed5",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}

View File

@@ -0,0 +1,602 @@
{
"version": "5",
"dialect": "mysql",
"id": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7",
"prevId": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_5m_tokens": {
"name": "cache_write_5m_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_1h_tokens": {
"name": "cache_write_1h_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}

View File

@@ -0,0 +1,595 @@
{
"version": "5",
"dialect": "mysql",
"id": "91067cc9-d492-47b3-932a-42dcc0920b3c",
"prevId": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_5m_tokens": {
"name": "cache_write_5m_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_1h_tokens": {
"name": "cache_write_1h_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}

View File

@@ -36,6 +36,27 @@
"when": 1757627357232,
"tag": "0004_first_mockingbird",
"breakpoints": true
},
{
"idx": 5,
"version": "5",
"when": 1757632304856,
"tag": "0005_jazzy_skrulls",
"breakpoints": true
},
{
"idx": 6,
"version": "5",
"when": 1757643108507,
"tag": "0006_parallel_gauntlet",
"breakpoints": true
},
{
"idx": 7,
"version": "5",
"when": 1757693869142,
"tag": "0007_familiar_nightshade",
"breakpoints": true
}
]
}

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode/cloud-core",
"version": "0.7.5",
"version": "0.9.0",
"private": true,
"type": "module",
"dependencies": {

View File

@@ -41,7 +41,11 @@ export namespace Key {
key: secretKey,
timeUsed: null,
}),
)
).catch((e: any) => {
if (e.message.match(/Duplicate entry '.*' for key 'key.name'/))
throw new Error("A key with this name already exists. Please choose a different name.")
throw e
})
return keyID
})

View File

@@ -1,4 +1,4 @@
import { bigint, boolean, int, mysqlTable, varchar } from "drizzle-orm/mysql-core"
import { bigint, boolean, int, mysqlTable, varchar, json } from "drizzle-orm/mysql-core"
import { timestamps, workspaceColumns } from "../drizzle/types"
import { workspaceIndexes } from "./workspace.sql"
@@ -34,12 +34,13 @@ export const UsageTable = mysqlTable(
...workspaceColumns,
...timestamps,
model: varchar("model", { length: 255 }).notNull(),
provider: varchar("provider", { length: 255 }),
provider: varchar("provider", { length: 255 }).notNull(),
inputTokens: int("input_tokens").notNull(),
outputTokens: int("output_tokens").notNull(),
reasoningTokens: int("reasoning_tokens"),
cacheReadTokens: int("cache_read_tokens"),
cacheWriteTokens: int("cache_write_tokens"),
cacheWrite5mTokens: int("cache_write_5m_tokens"),
cacheWrite1hTokens: int("cache_write_1h_tokens"),
cost: bigint("cost", { mode: "number" }).notNull(),
},
(table) => [...workspaceIndexes(table)],

View File

@@ -1,11 +1,11 @@
import { z } from "zod"
export function fn<T extends z.ZodType, Result>(schema: T, cb: (input: z.output<T>) => Result) {
const result = (input: z.input<T>) => {
export function fn<T extends z.ZodType, Result>(schema: T, cb: (input: z.infer<T>) => Result) {
const result = (input: z.infer<T>) => {
const parsed = schema.parse(input)
return cb(parsed)
}
result.force = (input: z.input<T>) => cb(input)
result.force = (input: z.infer<T>) => cb(input)
result.schema = schema
return result
}

View File

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

View File

@@ -1,12 +1,13 @@
{
"name": "@opencode/cloud-scripts",
"version": "0.7.5",
"version": "0.9.0",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
"scripts": {
"start": "tsx",
"shell": "sst shell"
"shell": "sst shell -- bun tsx",
"shell-dev": "sst shell --stage dev -- bun tsx",
"shell-prod": "sst shell --stage production -- bun tsx"
},
"dependencies": {
"@opencode/cloud-core": "workspace:*",

View File

@@ -0,0 +1,10 @@
import { Database, eq } from "@opencode/cloud-core/drizzle/index.js"
import { UsageTable } from "@opencode/cloud-core/schema/billing.sql.js"
await Database.use(async (tx) => {
await tx
.update(UsageTable)
.set({ model: "grok-code" })
.where(eq(UsageTable.model, "x-ai/grok-code-fast-1"))
.limit(90000)
})

View File

@@ -1 +0,0 @@
// placeholder

View File

@@ -24,7 +24,7 @@
"ai": "5.0.8",
"hono": "4.7.10",
"typescript": "5.8.2",
"zod": "3.25.76",
"zod": "4.1.8",
"remeda": "2.26.0",
"solid-js": "1.9.9"
}
@@ -33,8 +33,8 @@
"pulumi-stripe": "0.0.24"
},
"devDependencies": {
"prettier": "3.5.3",
"sst": "3.17.12"
"prettier": "3.6.2",
"sst": "3.17.13"
},
"repository": {
"type": "git",
@@ -54,7 +54,7 @@
"web-tree-sitter"
],
"overrides": {
"zod": "3.25.76"
"zod": "4.1.8"
},
"patchedDependencies": {
"@solidjs/start@1.1.7": "patches/@solidjs%2Fstart@1.1.7.patch"

View File

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

View File

@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "0.7.5",
"version": "0.9.0",
"name": "opencode",
"type": "module",
"private": true,
@@ -28,6 +28,7 @@
},
"dependencies": {
"@clack/prompts": "1.0.0-alpha.1",
"@hono/standard-validator": "0.1.5",
"@hono/zod-validator": "catalog:",
"@modelcontextprotocol/sdk": "1.15.1",
"@openauthjs/openauth": "0.4.3",
@@ -40,7 +41,7 @@
"diff": "8.0.2",
"gray-matter": "4.0.3",
"hono": "catalog:",
"hono-openapi": "0.4.8",
"hono-openapi": "1.0.7",
"ignore": "7.0.5",
"jsonc-parser": "3.3.1",
"minimatch": "10.0.3",
@@ -54,7 +55,6 @@
"web-tree-sitter": "0.22.6",
"xdg-basedir": "5.1.0",
"yargs": "18.0.0",
"zod": "catalog:",
"zod-openapi": "4.1.0"
"zod": "catalog:"
}
}

View File

@@ -1,13 +1,12 @@
#!/usr/bin/env bun
import "zod-openapi/extend"
import { z } from "zod/v4"
import { Config } from "../src/config/config"
import { zodToJsonSchema } from "zod-to-json-schema"
const file = process.argv[2]
console.log(file)
const result = zodToJsonSchema(Config.Info, {
const result = z.toJSONSchema(Config.Info, {
/**
* We'll use the `default` values of the field as the only value in `examples`.
* This will ensure no docs are needed to be read, as the configuration is
@@ -15,10 +14,8 @@ const result = zodToJsonSchema(Config.Info, {
*
* See https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.9.5
*/
postProcess(jsonSchema) {
const schema = jsonSchema as typeof jsonSchema & {
examples?: unknown[]
}
override(input) {
const schema = input.jsonSchema
if (schema && typeof schema === "object" && "type" in schema && schema.type === "string" && schema?.default) {
if (!schema.examples) {
schema.examples = [schema.default]
@@ -29,8 +26,6 @@ const result = zodToJsonSchema(Config.Info, {
.join("\n\n")
.trim()
}
return jsonSchema
},
}) as Record<string, unknown> & {
allowComments?: boolean

View File

@@ -1,5 +1,5 @@
import { Config } from "../config/config"
import z from "zod"
import z from "zod/v4"
import { Provider } from "../provider/provider"
import { generateObject, type ModelMessage } from "ai"
import PROMPT_GENERATE from "./generate.txt"
@@ -28,10 +28,10 @@ export namespace Agent {
})
.optional(),
prompt: z.string().optional(),
tools: z.record(z.boolean()),
tools: z.record(z.string(), z.boolean()),
options: z.record(z.string(), z.any()),
})
.openapi({
.meta({
ref: "Agent",
})
export type Info = z.infer<typeof Info>

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Auth } from "./index"
import { NamedError } from "../util/error"

View File

@@ -1,7 +1,7 @@
import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
import { z } from "zod"
import z from "zod/v4"
export namespace Auth {
export const Oauth = z
@@ -11,14 +11,14 @@ export namespace Auth {
access: z.string(),
expires: z.number(),
})
.openapi({ ref: "OAuth" })
.meta({ ref: "OAuth" })
export const Api = z
.object({
type: z.literal("api"),
key: z.string(),
})
.openapi({ ref: "ApiAuth" })
.meta({ ref: "ApiAuth" })
export const WellKnown = z
.object({
@@ -26,9 +26,9 @@ export namespace Auth {
key: z.string(),
token: z.string(),
})
.openapi({ ref: "WellKnownAuth" })
.meta({ ref: "WellKnownAuth" })
export const Info = z.discriminatedUnion("type", [Oauth, Api, WellKnown]).openapi({ ref: "Auth" })
export const Info = z.discriminatedUnion("type", [Oauth, Api, WellKnown]).meta({ ref: "Auth" })
export type Info = z.infer<typeof Info>
const filepath = path.join(Global.Path.data, "auth.json")

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Global } from "../global"
import { Log } from "../util/log"
import path from "path"

View File

@@ -1,4 +1,5 @@
import { z, type ZodType } from "zod"
import z from "zod/v4"
import type { ZodType } from "zod/v4"
import { Log } from "../util/log"
import { Instance } from "../project/instance"
@@ -38,7 +39,7 @@ export namespace Bus {
type: z.literal(type),
properties: def.properties,
})
.openapi({
.meta({
ref: "Event" + "." + def.type,
}),
)

View File

@@ -11,6 +11,7 @@ import { MessageV2 } from "../../session/message-v2"
import { Identifier } from "../../id/id"
import { Agent } from "../../agent/agent"
import { Command } from "../../command"
import { SessionPrompt } from "../../session/prompt"
const TOOL: Record<string, [string, string]> = {
todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD],
@@ -144,6 +145,7 @@ export const RunCommand = cmd({
}
let text = ""
Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
if (evt.properties.part.sessionID !== session.id) return
if (evt.properties.part.messageID === messageID) return
@@ -154,7 +156,13 @@ export const RunCommand = cmd({
const title =
part.state.title ||
(Object.keys(part.state.input).length > 0 ? JSON.stringify(part.state.input) : "Unknown")
printEvent(color, tool, title)
if (part.tool === "bash" && part.state.output && part.state.output.trim()) {
UI.println()
UI.println(part.state.output)
}
}
if (part.type === "text") {
@@ -185,7 +193,7 @@ export const RunCommand = cmd({
})
if (args.command) {
await Session.command({
await SessionPrompt.command({
messageID: Identifier.ascending("message"),
sessionID: session.id,
agent: agent.name,
@@ -197,7 +205,7 @@ export const RunCommand = cmd({
}
const messageID = Identifier.ascending("message")
const result = await Session.prompt({
const result = await SessionPrompt.prompt({
sessionID: session.id,
messageID,
model: {

View File

@@ -123,14 +123,15 @@ export const TuiCommand = cmd({
const file = Bun.file(binary)
if (!(await file.exists())) {
await Bun.write(file, tui, { mode: 0o755 })
await fs.chmod(binary, 0o755)
if (process.platform !== "win32") await fs.chmod(binary, 0o755)
}
cmd = [binary]
}
if (!tui) {
const dir = Bun.fileURLToPath(new URL("../../../../tui/cmd/opencode", import.meta.url))
await $`go build -o ./dist/tui ./main.go`.cwd(dir)
cmd = [path.join(dir, "dist/tui")]
let binaryName = `./dist/tui${process.platform === "win32" ? ".exe" : ""}`
await $`go build -o ${binaryName} ./main.go`.cwd(dir)
cmd = [path.join(dir, binaryName)]
}
Log.Default.info("tui", {
cmd,

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { EOL } from "os"
import { NamedError } from "../util/error"

View File

@@ -1,4 +1,4 @@
import z from "zod"
import z from "zod/v4"
import { Config } from "../config/config"
import { Instance } from "../project/instance"
@@ -10,8 +10,9 @@ export namespace Command {
agent: z.string().optional(),
model: z.string().optional(),
template: z.string(),
subtask: z.boolean().optional(),
})
.openapi({
.meta({
ref: "Command",
})
export type Info = z.infer<typeof Info>
@@ -28,6 +29,7 @@ export namespace Command {
model: command.model,
description: command.description,
template: command.template,
subtask: command.subtask,
}
}

View File

@@ -1,7 +1,7 @@
import { Log } from "../util/log"
import path from "path"
import os from "os"
import { z } from "zod"
import z from "zod/v4"
import { Filesystem } from "../util/filesystem"
import { ModelsDev } from "../provider/models"
import { mergeDeep, pipe } from "remeda"
@@ -217,7 +217,7 @@ export namespace Config {
enabled: z.boolean().optional().describe("Enable or disable the MCP server on startup"),
})
.strict()
.openapi({
.meta({
ref: "McpLocalConfig",
})
@@ -229,7 +229,7 @@ export namespace Config {
headers: z.record(z.string(), z.string()).optional().describe("Headers to send with the request"),
})
.strict()
.openapi({
.meta({
ref: "McpRemoteConfig",
})
@@ -244,6 +244,7 @@ export namespace Config {
description: z.string().optional(),
agent: z.string().optional(),
model: z.string().optional(),
subtask: z.boolean().optional(),
})
export type Command = z.infer<typeof Command>
@@ -266,7 +267,7 @@ export namespace Config {
.optional(),
})
.catchall(z.any())
.openapi({
.meta({
ref: "AgentConfig",
})
export type Agent = z.infer<typeof Agent>
@@ -341,7 +342,7 @@ export namespace Config {
messages_revert: z.string().optional().default("none").describe("@deprecated use messages_undo. Revert message"),
})
.strict()
.openapi({
.meta({
ref: "KeybindsConfig",
})
@@ -349,7 +350,7 @@ export namespace Config {
scroll_speed: z.number().min(1).optional().default(2).describe("TUI scroll speed"),
})
export const Layout = z.enum(["auto", "stretch"]).openapi({
export const Layout = z.enum(["auto", "stretch"]).meta({
ref: "LayoutConfig",
})
export type Layout = z.infer<typeof Layout>
@@ -406,9 +407,10 @@ export namespace Config {
.describe("Agent configuration, see https://opencode.ai/docs/agent"),
provider: z
.record(
z.string(),
ModelsDev.Provider.partial()
.extend({
models: z.record(ModelsDev.Model.partial()).optional(),
models: z.record(z.string(), ModelsDev.Model.partial()).optional(),
options: z
.object({
apiKey: z.string().optional(),
@@ -504,7 +506,7 @@ export namespace Config {
.optional(),
})
.strict()
.openapi({
.meta({
ref: "Config",
})
@@ -643,7 +645,7 @@ export namespace Config {
"ConfigInvalidError",
z.object({
path: z.string(),
issues: z.custom<z.ZodIssue[]>().optional(),
issues: z.custom<z.core.$ZodIssue[]>().optional(),
message: z.string().optional(),
}),
)

View File

@@ -1,7 +1,7 @@
import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
import { z } from "zod"
import z from "zod/v4"
import { NamedError } from "../util/error"
import { lazy } from "../util/lazy"
import { Log } from "../util/log"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Bus } from "../bus"
import { $ } from "bun"
import { formatPatch, structuredPatch } from "diff"
@@ -18,7 +18,7 @@ export namespace File {
removed: z.number().int(),
status: z.enum(["added", "deleted", "modified"]),
})
.openapi({
.meta({
ref: "File",
})
@@ -32,7 +32,7 @@ export namespace File {
type: z.enum(["file", "directory"]),
ignored: z.boolean(),
})
.openapi({
.meta({
ref: "FileNode",
})
export type Node = z.infer<typeof Node>
@@ -60,7 +60,7 @@ export namespace File {
})
.optional(),
})
.openapi({
.meta({
ref: "FileContent",
})
export type Content = z.infer<typeof Content>

View File

@@ -2,7 +2,7 @@
import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
import { z } from "zod"
import z from "zod/v4"
import { NamedError } from "../util/error"
import { lazy } from "../util/lazy"
import { $ } from "bun"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Bus } from "../bus"
import fs from "fs"
import { Log } from "../util/log"

View File

@@ -8,6 +8,7 @@ export namespace Flag {
export const OPENCODE_DISABLE_DEFAULT_PLUGINS = truthy("OPENCODE_DISABLE_DEFAULT_PLUGINS")
export const OPENCODE_DISABLE_LSP_DOWNLOAD = truthy("OPENCODE_DISABLE_LSP_DOWNLOAD")
export const OPENCODE_ENABLE_EXPERIMENTAL_MODELS = truthy("OPENCODE_ENABLE_EXPERIMENTAL_MODELS")
export const OPENCODE_DISABLE_AUTOCOMPACT = truthy("OPENCODE_DISABLE_AUTOCOMPACT")
function truthy(key: string) {
const value = process.env[key]?.toLowerCase()

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { randomBytes } from "crypto"
export namespace Identifier {

View File

@@ -1,5 +1,5 @@
import { spawn } from "bun"
import { z } from "zod"
import z from "zod/v4"
import { NamedError } from "../util/error"
import { Log } from "../util/log"
import { Bus } from "../bus"

View File

@@ -1,4 +1,3 @@
import "zod-openapi/extend"
import yargs from "yargs"
import { hideBin } from "yargs/helpers"
import { RunCommand } from "./cli/cmd/run"

View File

@@ -1,6 +1,6 @@
import path from "path"
import { $ } from "bun"
import { z } from "zod"
import z from "zod/v4"
import { NamedError } from "../util/error"
import { Bus } from "../bus"
import { Log } from "../util/log"
@@ -28,7 +28,7 @@ export namespace Installation {
version: z.string(),
latest: z.string(),
})
.openapi({
.meta({
ref: "InstallationInfo",
})
export type Info = z.infer<typeof Info>

View File

@@ -4,7 +4,7 @@ import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types
import { Log } from "../util/log"
import { LANGUAGE_EXTENSIONS } from "./language"
import { Bus } from "../bus"
import z from "zod"
import z from "zod/v4"
import type { LSPServer } from "./server"
import { NamedError } from "../util/error"
import { withTimeout } from "../util/timeout"

View File

@@ -2,7 +2,7 @@ import { Log } from "../util/log"
import { LSPClient } from "./client"
import path from "path"
import { LSPServer } from "./server"
import { z } from "zod"
import z from "zod/v4"
import { Config } from "../config/config"
import { spawn } from "child_process"
import { Instance } from "../project/instance"
@@ -21,7 +21,7 @@ export namespace LSP {
character: z.number(),
}),
})
.openapi({
.meta({
ref: "Range",
})
export type Range = z.infer<typeof Range>
@@ -35,7 +35,7 @@ export namespace LSP {
range: Range,
}),
})
.openapi({
.meta({
ref: "Symbol",
})
export type Symbol = z.infer<typeof Symbol>
@@ -48,7 +48,7 @@ export namespace LSP {
range: Range,
selectionRange: Range,
})
.openapi({
.meta({
ref: "DocumentSymbol",
})
export type DocumentSymbol = z.infer<typeof DocumentSymbol>

View File

@@ -5,7 +5,7 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
import { Config } from "../config/config"
import { Log } from "../util/log"
import { NamedError } from "../util/error"
import { z } from "zod"
import z from "zod/v4"
import { Session } from "../session"
import { Bus } from "../bus"
import { Instance } from "../project/instance"

View File

@@ -1,28 +1,38 @@
import { z } from "zod"
import z from "zod/v4"
import { Bus } from "../bus"
import { Log } from "../util/log"
import { Identifier } from "../id/id"
import { Plugin } from "../plugin"
import { Instance } from "../project/instance"
import { Wildcard } from "../util/wildcard"
export namespace Permission {
const log = Log.create({ service: "permission" })
function toKeys(pattern: Info["pattern"], type: string): string[] {
return pattern === undefined ? [type] : Array.isArray(pattern) ? pattern : [pattern]
}
function covered(keys: string[], approved: Record<string, boolean>): boolean {
const pats = Object.keys(approved)
return keys.every((k) => pats.some((p) => Wildcard.match(k, p)))
}
export const Info = z
.object({
id: z.string(),
type: z.string(),
pattern: z.string().optional(),
pattern: z.union([z.string(), z.array(z.string())]).optional(),
sessionID: z.string(),
messageID: z.string(),
callID: z.string().optional(),
title: z.string(),
metadata: z.record(z.any()),
metadata: z.record(z.string(), z.any()),
time: z.object({
created: z.number(),
}),
})
.openapi({
.meta({
ref: "Permission",
})
export type Info = z.infer<typeof Info>
@@ -83,7 +93,9 @@ export namespace Permission {
toolCallID: input.callID,
pattern: input.pattern,
})
if (approved[input.sessionID]?.[input.pattern ?? input.type]) return
const approvedForSession = approved[input.sessionID] || {}
const keys = toKeys(input.pattern, input.type)
if (covered(keys, approvedForSession)) return
const info: Info = {
id: Identifier.ascending("permission"),
type: input.type,
@@ -141,9 +153,15 @@ export namespace Permission {
})
if (input.response === "always") {
approved[input.sessionID] = approved[input.sessionID] || {}
approved[input.sessionID][match.info.pattern ?? match.info.type] = true
for (const item of Object.values(pending[input.sessionID])) {
if ((item.info.pattern ?? item.info.type) === (match.info.pattern ?? match.info.type)) {
const approveKeys = toKeys(match.info.pattern, match.info.type)
for (const k of approveKeys) {
approved[input.sessionID][k] = true
}
const items = pending[input.sessionID]
if (!items) return
for (const item of Object.values(items)) {
const itemKeys = toKeys(item.info.pattern, item.info.type)
if (covered(itemKeys, approved[input.sessionID])) {
respond({ sessionID: item.info.sessionID, permissionID: item.info.id, response: input.response })
}
}

View File

@@ -1,4 +1,4 @@
import z from "zod"
import z from "zod/v4"
import { Filesystem } from "../util/filesystem"
import path from "path"
import { $ } from "bun"
@@ -17,7 +17,7 @@ export namespace Project {
initialized: z.number().optional(),
}),
})
.openapi({
.meta({
ref: "Project",
})
export type Info = z.infer<typeof Info>

View File

@@ -1,7 +1,7 @@
import { Global } from "../global"
import { Log } from "../util/log"
import path from "path"
import { z } from "zod"
import z from "zod/v4"
import { data } from "./models-macro" with { type: "macro" }
import { Installation } from "../installation"
@@ -29,10 +29,10 @@ export namespace ModelsDev {
output: z.number(),
}),
experimental: z.boolean().optional(),
options: z.record(z.any()),
options: z.record(z.string(), z.any()),
provider: z.object({ npm: z.string() }).optional(),
})
.openapi({
.meta({
ref: "Model",
})
export type Model = z.infer<typeof Model>
@@ -44,9 +44,9 @@ export namespace ModelsDev {
env: z.array(z.string()),
id: z.string(),
npm: z.string().optional(),
models: z.record(Model),
models: z.record(z.string(), Model),
})
.openapi({
.meta({
ref: "Provider",
})

View File

@@ -1,4 +1,4 @@
import z from "zod"
import z from "zod/v4"
import path from "path"
import { Config } from "../config/config"
import { mergeDeep, sortBy } from "remeda"

View File

@@ -1,5 +1,6 @@
import type { ModelMessage } from "ai"
import { unique } from "remeda"
import type { JSONSchema } from "zod/v4/core"
export namespace ProviderTransform {
function normalizeToolCallIds(msgs: ModelMessage[]): ModelMessage[] {
@@ -112,4 +113,29 @@ export namespace ProviderTransform {
}
return outputLimit
}
export function schema(_providerID: string, _modelID: string, schema: JSONSchema.BaseSchema) {
/*
if (["openai", "azure"].includes(providerID)) {
if (schema.type === "object" && schema.properties) {
for (const [key, value] of Object.entries(schema.properties)) {
if (schema.required?.includes(key)) continue
schema.properties[key] = {
anyOf: [
value as JSONSchema.JSONSchema,
{
type: "null",
},
],
}
}
}
}
if (providerID === "google") {
}
*/
return schema
}
}

View File

@@ -1,6 +1,6 @@
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver } from "hono-openapi/zod"
import { resolver } from "hono-openapi"
import { Instance } from "../project/instance"
import { Project } from "../project/project"

View File

@@ -1,11 +1,10 @@
import { Log } from "../util/log"
import { Bus } from "../bus"
import { describeRoute, generateSpecs, openAPISpecs } from "hono-openapi"
import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi"
import { Hono } from "hono"
import { streamSSE } from "hono/streaming"
import { Session } from "../session"
import { resolver, validator as zValidator } from "hono-openapi/zod"
import { z } from "zod"
import z from "zod/v4"
import { Provider } from "../provider/provider"
import { mapValues } from "remeda"
import { NamedError } from "../util/error"
@@ -25,6 +24,9 @@ import { Global } from "../global"
import { ProjectRoute } from "./project"
import { ToolRegistry } from "../tool/registry"
import { zodToJsonSchema } from "zod-to-json-schema"
import { SessionPrompt } from "../session/prompt"
import { SessionCompaction } from "../session/compaction"
import { SessionRevert } from "../session/revert"
const ERRORS = {
400: {
@@ -36,7 +38,7 @@ const ERRORS = {
.object({
data: z.record(z.string(), z.any()),
})
.openapi({
.meta({
ref: "Error",
}),
),
@@ -56,7 +58,7 @@ export namespace Server {
optional: z.boolean().optional(),
items: z.enum(["string", "number", "boolean"]).optional(),
})
.openapi({ ref: "HttpParamSpec" })
.meta({ ref: "HttpParamSpec" })
const HttpToolRegistration = z
.object({
@@ -64,12 +66,12 @@ export namespace Server {
description: z.string(),
parameters: z.object({
type: z.literal("object"),
properties: z.record(HttpParamSpec),
properties: z.record(z.string(), HttpParamSpec),
}),
callbackUrl: z.string(),
headers: z.record(z.string(), z.string()).optional(),
})
.openapi({ ref: "HttpToolRegistration" })
.meta({ ref: "HttpToolRegistration" })
export const Event = {
Connected: Bus.event("server.connected", z.object({})),
@@ -112,10 +114,9 @@ export namespace Server {
return next()
})
})
.use(zValidator("query", z.object({ directory: z.string().optional() })))
.get(
"/doc",
openAPISpecs(app, {
openAPIRouteHandler(app, {
documentation: {
info: {
title: "opencode",
@@ -126,6 +127,7 @@ export namespace Server {
},
}),
)
.use(validator("query", z.object({ directory: z.string().optional() })))
.route("/project", ProjectRoute)
.get(
"/event",
@@ -138,7 +140,7 @@ export namespace Server {
content: {
"text/event-stream": {
schema: resolver(
Bus.payloads().openapi({
Bus.payloads().meta({
ref: "Event",
}),
),
@@ -208,7 +210,7 @@ export namespace Server {
...ERRORS,
},
}),
zValidator("json", HttpToolRegistration),
validator("json", HttpToolRegistration),
async (c) => {
ToolRegistry.registerHTTP(c.req.valid("json"))
return c.json(true)
@@ -224,7 +226,7 @@ export namespace Server {
description: "Tool IDs",
content: {
"application/json": {
schema: resolver(z.array(z.string()).openapi({ ref: "ToolIDs" })),
schema: resolver(z.array(z.string()).meta({ ref: "ToolIDs" })),
},
},
},
@@ -254,9 +256,9 @@ export namespace Server {
description: z.string(),
parameters: z.any(),
})
.openapi({ ref: "ToolListItem" }),
.meta({ ref: "ToolListItem" }),
)
.openapi({ ref: "ToolList" }),
.meta({ ref: "ToolList" }),
),
},
},
@@ -264,7 +266,7 @@ export namespace Server {
...ERRORS,
},
}),
zValidator(
validator(
"query",
z.object({
provider: z.string(),
@@ -302,7 +304,7 @@ export namespace Server {
worktree: z.string(),
directory: z.string(),
})
.openapi({
.meta({
ref: "Path",
}),
),
@@ -358,7 +360,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
@@ -386,7 +388,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
@@ -415,7 +417,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"json",
z
.object({
@@ -446,7 +448,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
@@ -473,13 +475,13 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
}),
),
zValidator(
validator(
"json",
z.object({
title: z.string().optional(),
@@ -514,13 +516,13 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
id: z.string().meta({ description: "Session ID" }),
}),
),
zValidator(
validator(
"json",
z.object({
messageID: z.string(),
@@ -551,14 +553,14 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
}),
),
async (c) => {
return c.json(Session.abort(c.req.valid("param").id))
return c.json(SessionPrompt.abort(c.req.valid("param").id))
},
)
.post(
@@ -577,7 +579,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
@@ -606,7 +608,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
@@ -635,13 +637,13 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
id: z.string().meta({ description: "Session ID" }),
}),
),
zValidator(
validator(
"json",
z.object({
providerID: z.string(),
@@ -651,7 +653,7 @@ export namespace Server {
async (c) => {
const id = c.req.valid("param").id
const body = c.req.valid("json")
await Session.summarize({ ...body, sessionID: id })
await SessionCompaction.run({ ...body, sessionID: id })
return c.json(true)
},
)
@@ -665,23 +667,16 @@ export namespace Server {
description: "List of messages",
content: {
"application/json": {
schema: resolver(
z
.object({
info: MessageV2.Info,
parts: MessageV2.Part.array(),
})
.array(),
),
schema: resolver(MessageV2.WithParts.array()),
},
},
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
id: z.string().meta({ description: "Session ID" }),
}),
),
async (c) => {
@@ -710,11 +705,11 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
messageID: z.string().openapi({ description: "Message ID" }),
id: z.string().meta({ description: "Session ID" }),
messageID: z.string().meta({ description: "Message ID" }),
}),
),
async (c) => {
@@ -744,17 +739,17 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
id: z.string().meta({ description: "Session ID" }),
}),
),
zValidator("json", Session.PromptInput.omit({ sessionID: true })),
validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })),
async (c) => {
const sessionID = c.req.valid("param").id
const body = c.req.valid("json")
const msg = await Session.prompt({ ...body, sessionID })
const msg = await SessionPrompt.prompt({ ...body, sessionID })
return c.json(msg)
},
)
@@ -779,17 +774,17 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
id: z.string().meta({ description: "Session ID" }),
}),
),
zValidator("json", Session.CommandInput.omit({ sessionID: true })),
validator("json", SessionPrompt.CommandInput.omit({ sessionID: true })),
async (c) => {
const sessionID = c.req.valid("param").id
const body = c.req.valid("json")
const msg = await Session.command({ ...body, sessionID })
const msg = await SessionPrompt.command({ ...body, sessionID })
return c.json(msg)
},
)
@@ -809,17 +804,17 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
id: z.string().meta({ description: "Session ID" }),
}),
),
zValidator("json", Session.ShellInput.omit({ sessionID: true })),
validator("json", SessionPrompt.ShellInput.omit({ sessionID: true })),
async (c) => {
const sessionID = c.req.valid("param").id
const body = c.req.valid("json")
const msg = await Session.shell({ ...body, sessionID })
const msg = await SessionPrompt.shell({ ...body, sessionID })
return c.json(msg)
},
)
@@ -839,17 +834,17 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
}),
),
zValidator("json", Session.RevertInput.omit({ sessionID: true })),
validator("json", SessionRevert.RevertInput.omit({ sessionID: true })),
async (c) => {
const id = c.req.valid("param").id
log.info("revert", c.req.valid("json"))
const session = await Session.revert({ sessionID: id, ...c.req.valid("json") })
const session = await SessionRevert.revert({ sessionID: id, ...c.req.valid("json") })
return c.json(session)
},
)
@@ -869,7 +864,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
@@ -877,7 +872,7 @@ export namespace Server {
),
async (c) => {
const id = c.req.valid("param").id
const session = await Session.unrevert({ sessionID: id })
const session = await SessionRevert.unrevert({ sessionID: id })
return c.json(session)
},
)
@@ -896,14 +891,14 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
permissionID: z.string(),
}),
),
zValidator("json", z.object({ response: Permission.Response })),
validator("json", z.object({ response: Permission.Response })),
async (c) => {
const params = c.req.valid("param")
const id = params.id
@@ -978,7 +973,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"query",
z.object({
pattern: z.string(),
@@ -1010,7 +1005,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"query",
z.object({
query: z.string(),
@@ -1042,7 +1037,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"query",
z.object({
query: z.string(),
@@ -1070,7 +1065,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"query",
z.object({
path: z.string(),
@@ -1098,7 +1093,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"query",
z.object({
path: z.string(),
@@ -1147,16 +1142,16 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"json",
z.object({
service: z.string().openapi({ description: "Service name for the log entry" }),
level: z.enum(["debug", "info", "error", "warn"]).openapi({ description: "Log level" }),
message: z.string().openapi({ description: "Log message" }),
service: z.string().meta({ description: "Service name for the log entry" }),
level: z.enum(["debug", "info", "error", "warn"]).meta({ description: "Log level" }),
message: z.string().meta({ description: "Log message" }),
extra: z
.record(z.string(), z.any())
.optional()
.openapi({ description: "Additional metadata for the log entry" }),
.meta({ description: "Additional metadata for the log entry" }),
}),
),
async (c) => {
@@ -1218,7 +1213,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"json",
z.object({
text: z.string(),
@@ -1350,7 +1345,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"json",
z.object({
command: z.string(),
@@ -1374,7 +1369,7 @@ export namespace Server {
},
},
}),
zValidator(
validator(
"json",
z.object({
title: z.string().optional(),
@@ -1402,13 +1397,13 @@ export namespace Server {
...ERRORS,
},
}),
zValidator(
validator(
"param",
z.object({
id: z.string(),
}),
),
zValidator("json", Auth.Info),
validator("json", Auth.Info),
async (c) => {
const id = c.req.valid("param").id
const info = c.req.valid("json")

View File

@@ -0,0 +1,124 @@
import { generateText, type ModelMessage } from "ai"
import { Session } from "."
import { Identifier } from "../id/id"
import { Instance } from "../project/instance"
import { Provider } from "../provider/provider"
import { defer } from "../util/defer"
import { MessageV2 } from "./message-v2"
import { SystemPrompt } from "./system"
import { Bus } from "../bus"
import z from "zod/v4"
import type { ModelsDev } from "../provider/models"
import { SessionPrompt } from "./prompt"
import { Flag } from "../flag/flag"
export namespace SessionCompaction {
export const Event = {
Compacted: Bus.event(
"session.compacted",
z.object({
sessionID: z.string(),
}),
),
}
export function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: ModelsDev.Model }) {
if (Flag.OPENCODE_DISABLE_AUTOCOMPACT) return false
const context = input.model.limit.context
if (context === 0) return false
const count = input.tokens.input + input.tokens.cache.read + input.tokens.output
const output = Math.min(input.model.limit.output, SessionPrompt.OUTPUT_TOKEN_MAX) || SessionPrompt.OUTPUT_TOKEN_MAX
const usable = context - output
return count > usable
}
export async function run(input: { sessionID: string; providerID: string; modelID: string }) {
await Session.update(input.sessionID, (draft) => {
draft.time.compacting = Date.now()
})
await using _ = defer(async () => {
await Session.update(input.sessionID, (draft) => {
draft.time.compacting = undefined
})
})
const toSummarize = await Session.messages(input.sessionID).then(MessageV2.filterSummarized)
const model = await Provider.getModel(input.providerID, input.modelID)
const system = [
...SystemPrompt.summarize(model.providerID),
...(await SystemPrompt.environment()),
...(await SystemPrompt.custom()),
]
const msg = (await Session.updateMessage({
id: Identifier.ascending("message"),
role: "assistant",
sessionID: input.sessionID,
system,
mode: "build",
path: {
cwd: Instance.directory,
root: Instance.worktree,
},
cost: 0,
tokens: {
output: 0,
input: 0,
reasoning: 0,
cache: { read: 0, write: 0 },
},
modelID: input.modelID,
providerID: model.providerID,
time: {
created: Date.now(),
},
})) as MessageV2.Assistant
const generated = await generateText({
maxRetries: 10,
model: model.language,
messages: [
...system.map(
(x): ModelMessage => ({
role: "system",
content: x,
}),
),
...MessageV2.toModelMessage(toSummarize),
{
role: "user",
content: [
{
type: "text",
text: "Provide a detailed but concise summary of our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next.",
},
],
},
],
})
const usage = Session.getUsage(model.info, generated.usage, generated.providerMetadata)
msg.cost += usage.cost
msg.tokens = usage.tokens
msg.summary = true
msg.time.completed = Date.now()
await Session.updateMessage(msg)
const part = await Session.updatePart({
type: "text",
sessionID: input.sessionID,
messageID: msg.id,
id: Identifier.ascending("part"),
text: generated.text,
time: {
start: Date.now(),
end: Date.now(),
},
})
Bus.publish(Event.Compacted, {
sessionID: input.sessionID,
})
return {
info: msg,
parts: [part],
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import z from "zod"
import z from "zod/v4"
import { Bus } from "../bus"
import { NamedError } from "../util/error"
import { Message } from "./message"
@@ -8,7 +8,7 @@ import { LSP } from "../lsp"
export namespace MessageV2 {
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
export const AbortedError = NamedError.create("MessageAbortedError", z.object({}))
export const AbortedError = NamedError.create("MessageAbortedError", z.object({ message: z.string() }))
export const AuthError = NamedError.create(
"ProviderAuthError",
z.object({
@@ -21,7 +21,7 @@ export namespace MessageV2 {
.object({
status: z.literal("pending"),
})
.openapi({
.meta({
ref: "ToolStatePending",
})
@@ -32,12 +32,12 @@ export namespace MessageV2 {
status: z.literal("running"),
input: z.any(),
title: z.string().optional(),
metadata: z.record(z.any()).optional(),
metadata: z.record(z.string(), z.any()).optional(),
time: z.object({
start: z.number(),
}),
})
.openapi({
.meta({
ref: "ToolStateRunning",
})
export type ToolStateRunning = z.infer<typeof ToolStateRunning>
@@ -45,16 +45,17 @@ export namespace MessageV2 {
export const ToolStateCompleted = z
.object({
status: z.literal("completed"),
input: z.record(z.any()),
input: z.record(z.string(), z.any()),
output: z.string(),
title: z.string(),
metadata: z.record(z.any()),
metadata: z.record(z.string(), z.any()),
time: z.object({
start: z.number(),
end: z.number(),
compacted: z.number().optional(),
}),
})
.openapi({
.meta({
ref: "ToolStateCompleted",
})
export type ToolStateCompleted = z.infer<typeof ToolStateCompleted>
@@ -62,22 +63,22 @@ export namespace MessageV2 {
export const ToolStateError = z
.object({
status: z.literal("error"),
input: z.record(z.any()),
input: z.record(z.string(), z.any()),
error: z.string(),
metadata: z.record(z.any()).optional(),
metadata: z.record(z.string(), z.any()).optional(),
time: z.object({
start: z.number(),
end: z.number(),
}),
})
.openapi({
.meta({
ref: "ToolStateError",
})
export type ToolStateError = z.infer<typeof ToolStateError>
export const ToolState = z
.discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError])
.openapi({
.meta({
ref: "ToolState",
})
@@ -90,7 +91,7 @@ export namespace MessageV2 {
export const SnapshotPart = PartBase.extend({
type: z.literal("snapshot"),
snapshot: z.string(),
}).openapi({
}).meta({
ref: "SnapshotPart",
})
export type SnapshotPart = z.infer<typeof SnapshotPart>
@@ -99,7 +100,7 @@ export namespace MessageV2 {
type: z.literal("patch"),
hash: z.string(),
files: z.string().array(),
}).openapi({
}).meta({
ref: "PatchPart",
})
export type PatchPart = z.infer<typeof PatchPart>
@@ -114,7 +115,7 @@ export namespace MessageV2 {
end: z.number().optional(),
})
.optional(),
}).openapi({
}).meta({
ref: "TextPart",
})
export type TextPart = z.infer<typeof TextPart>
@@ -122,12 +123,12 @@ export namespace MessageV2 {
export const ReasoningPart = PartBase.extend({
type: z.literal("reasoning"),
text: z.string(),
metadata: z.record(z.any()).optional(),
metadata: z.record(z.string(), z.any()).optional(),
time: z.object({
start: z.number(),
end: z.number().optional(),
}),
}).openapi({
}).meta({
ref: "ReasoningPart",
})
export type ReasoningPart = z.infer<typeof ReasoningPart>
@@ -137,7 +138,7 @@ export namespace MessageV2 {
callID: z.string(),
tool: z.string(),
state: ToolState,
}).openapi({
}).meta({
ref: "ToolPart",
})
export type ToolPart = z.infer<typeof ToolPart>
@@ -149,7 +150,7 @@ export namespace MessageV2 {
start: z.number().int(),
end: z.number().int(),
})
.openapi({
.meta({
ref: "FilePartSourceText",
}),
})
@@ -157,7 +158,7 @@ export namespace MessageV2 {
export const FileSource = FilePartSourceBase.extend({
type: z.literal("file"),
path: z.string(),
}).openapi({
}).meta({
ref: "FileSource",
})
@@ -167,11 +168,11 @@ export namespace MessageV2 {
range: LSP.Range,
name: z.string(),
kind: z.number().int(),
}).openapi({
}).meta({
ref: "SymbolSource",
})
export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource]).openapi({
export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource]).meta({
ref: "FilePartSource",
})
@@ -181,7 +182,7 @@ export namespace MessageV2 {
filename: z.string().optional(),
url: z.string(),
source: FilePartSource.optional(),
}).openapi({
}).meta({
ref: "FilePart",
})
export type FilePart = z.infer<typeof FilePart>
@@ -196,14 +197,14 @@ export namespace MessageV2 {
end: z.number().int(),
})
.optional(),
}).openapi({
}).meta({
ref: "AgentPart",
})
export type AgentPart = z.infer<typeof AgentPart>
export const StepStartPart = PartBase.extend({
type: z.literal("step-start"),
}).openapi({
}).meta({
ref: "StepStartPart",
})
export type StepStartPart = z.infer<typeof StepStartPart>
@@ -220,7 +221,7 @@ export namespace MessageV2 {
write: z.number(),
}),
}),
}).openapi({
}).meta({
ref: "StepFinishPart",
})
export type StepFinishPart = z.infer<typeof StepFinishPart>
@@ -235,7 +236,7 @@ export namespace MessageV2 {
time: z.object({
created: z.number(),
}),
}).openapi({
}).meta({
ref: "UserMessage",
})
export type User = z.infer<typeof User>
@@ -252,7 +253,7 @@ export namespace MessageV2 {
PatchPart,
AgentPart,
])
.openapi({
.meta({
ref: "Part",
})
export type Part = z.infer<typeof Part>
@@ -290,12 +291,12 @@ export namespace MessageV2 {
write: z.number(),
}),
}),
}).openapi({
}).meta({
ref: "AssistantMessage",
})
export type Assistant = z.infer<typeof Assistant>
export const Info = z.discriminatedUnion("role", [User, Assistant]).openapi({
export const Info = z.discriminatedUnion("role", [User, Assistant]).meta({
ref: "Message",
})
export type Info = z.infer<typeof Info>
@@ -330,6 +331,12 @@ export namespace MessageV2 {
),
}
export const WithParts = z.object({
info: Info,
parts: z.array(Part),
})
export type WithParts = z.infer<typeof WithParts>
export function fromV1(v1: Message.Info) {
if (v1.role === "assistant") {
const info: Assistant = {
@@ -528,7 +535,7 @@ export namespace MessageV2 {
state: "output-available",
toolCallId: part.callID,
input: part.state.input,
output: part.state.output,
output: part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output,
},
]
if (part.state.status === "error")
@@ -542,6 +549,15 @@ export namespace MessageV2 {
},
]
}
if (part.type === "reasoning") {
return [
{
type: "reasoning",
text: part.text,
providerMetadata: part.metadata,
},
]
}
return []
}),
@@ -551,4 +567,10 @@ export namespace MessageV2 {
return convertToModelMessages(result)
}
export function filterSummarized(msgs: { info: MessageV2.Info; parts: MessageV2.Part[] }[]) {
const i = msgs.findLastIndex((m) => m.info.role === "assistant" && !!m.info.summary)
if (i === -1) return msgs.slice()
return msgs.slice(i)
}
}

View File

@@ -1,4 +1,4 @@
import z from "zod"
import z from "zod/v4"
import { NamedError } from "../util/error"
export namespace Message {
@@ -19,7 +19,7 @@ export namespace Message {
toolName: z.string(),
args: z.custom<Required<unknown>>(),
})
.openapi({
.meta({
ref: "ToolCall",
})
export type ToolCall = z.infer<typeof ToolCall>
@@ -32,7 +32,7 @@ export namespace Message {
toolName: z.string(),
args: z.custom<Required<unknown>>(),
})
.openapi({
.meta({
ref: "ToolPartialCall",
})
export type ToolPartialCall = z.infer<typeof ToolPartialCall>
@@ -46,12 +46,12 @@ export namespace Message {
args: z.custom<Required<unknown>>(),
result: z.string(),
})
.openapi({
.meta({
ref: "ToolResult",
})
export type ToolResult = z.infer<typeof ToolResult>
export const ToolInvocation = z.discriminatedUnion("state", [ToolCall, ToolPartialCall, ToolResult]).openapi({
export const ToolInvocation = z.discriminatedUnion("state", [ToolCall, ToolPartialCall, ToolResult]).meta({
ref: "ToolInvocation",
})
export type ToolInvocation = z.infer<typeof ToolInvocation>
@@ -61,7 +61,7 @@ export namespace Message {
type: z.literal("text"),
text: z.string(),
})
.openapi({
.meta({
ref: "TextPart",
})
export type TextPart = z.infer<typeof TextPart>
@@ -70,9 +70,9 @@ export namespace Message {
.object({
type: z.literal("reasoning"),
text: z.string(),
providerMetadata: z.record(z.any()).optional(),
providerMetadata: z.record(z.string(), z.any()).optional(),
})
.openapi({
.meta({
ref: "ReasoningPart",
})
export type ReasoningPart = z.infer<typeof ReasoningPart>
@@ -82,7 +82,7 @@ export namespace Message {
type: z.literal("tool-invocation"),
toolInvocation: ToolInvocation,
})
.openapi({
.meta({
ref: "ToolInvocationPart",
})
export type ToolInvocationPart = z.infer<typeof ToolInvocationPart>
@@ -93,9 +93,9 @@ export namespace Message {
sourceId: z.string(),
url: z.string(),
title: z.string().optional(),
providerMetadata: z.record(z.any()).optional(),
providerMetadata: z.record(z.string(), z.any()).optional(),
})
.openapi({
.meta({
ref: "SourceUrlPart",
})
export type SourceUrlPart = z.infer<typeof SourceUrlPart>
@@ -107,7 +107,7 @@ export namespace Message {
filename: z.string().optional(),
url: z.string(),
})
.openapi({
.meta({
ref: "FilePart",
})
export type FilePart = z.infer<typeof FilePart>
@@ -116,14 +116,14 @@ export namespace Message {
.object({
type: z.literal("step-start"),
})
.openapi({
.meta({
ref: "StepStartPart",
})
export type StepStartPart = z.infer<typeof StepStartPart>
export const MessagePart = z
.discriminatedUnion("type", [TextPart, ReasoningPart, ToolInvocationPart, SourceUrlPart, FilePart, StepStartPart])
.openapi({
.meta({
ref: "MessagePart",
})
export type MessagePart = z.infer<typeof MessagePart>
@@ -180,9 +180,9 @@ export namespace Message {
.optional(),
snapshot: z.string().optional(),
})
.openapi({ ref: "MessageMetadata" }),
.meta({ ref: "MessageMetadata" }),
})
.openapi({
.meta({
ref: "Message",
})
export type Info = z.infer<typeof Info>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
import z from "zod/v4"
import { Identifier } from "../id/id"
import { Snapshot } from "../snapshot"
import { MessageV2 } from "./message-v2"
import { Session } from "."
import { Log } from "../util/log"
import { splitWhen } from "remeda"
import { Storage } from "../storage/storage"
import { Bus } from "../bus"
export namespace SessionRevert {
const log = Log.create({ service: "session.revert" })
export const RevertInput = z.object({
sessionID: Identifier.schema("session"),
messageID: Identifier.schema("message"),
partID: Identifier.schema("part").optional(),
})
export type RevertInput = z.infer<typeof RevertInput>
export async function revert(input: RevertInput) {
const all = await Session.messages(input.sessionID)
let lastUser: MessageV2.User | undefined
const session = await Session.get(input.sessionID)
let revert: Session.Info["revert"]
const patches: Snapshot.Patch[] = []
for (const msg of all) {
if (msg.info.role === "user") lastUser = msg.info
const remaining = []
for (const part of msg.parts) {
if (revert) {
if (part.type === "patch") {
patches.push(part)
}
continue
}
if (!revert) {
if ((msg.info.id === input.messageID && !input.partID) || part.id === input.partID) {
// if no useful parts left in message, same as reverting whole message
const partID = remaining.some((item) => ["text", "tool"].includes(item.type)) ? input.partID : undefined
revert = {
messageID: !partID && lastUser ? lastUser.id : msg.info.id,
partID,
}
}
remaining.push(part)
}
}
}
if (revert) {
const session = await Session.get(input.sessionID)
revert.snapshot = session.revert?.snapshot ?? (await Snapshot.track())
await Snapshot.revert(patches)
if (revert.snapshot) revert.diff = await Snapshot.diff(revert.snapshot)
return Session.update(input.sessionID, (draft) => {
draft.revert = revert
})
}
return session
}
export async function unrevert(input: { sessionID: string }) {
log.info("unreverting", input)
const session = await Session.get(input.sessionID)
if (!session.revert) return session
if (session.revert.snapshot) await Snapshot.restore(session.revert.snapshot)
const next = await Session.update(input.sessionID, (draft) => {
draft.revert = undefined
})
return next
}
export async function cleanup(session: Session.Info) {
if (!session.revert) return
const sessionID = session.id
let msgs = await Session.messages(sessionID)
const messageID = session.revert.messageID
const [preserve, remove] = splitWhen(msgs, (x) => x.info.id === messageID)
msgs = preserve
for (const msg of remove) {
await Storage.remove(["message", sessionID, msg.info.id])
await Bus.publish(MessageV2.Event.Removed, { sessionID: sessionID, messageID: msg.info.id })
}
const last = preserve.at(-1)
if (session.revert.partID && last) {
const partID = session.revert.partID
const [preserveParts, removeParts] = splitWhen(last.parts, (x) => x.id === partID)
last.parts = preserveParts
for (const part of removeParts) {
await Storage.remove(["part", last.info.id, part.id])
await Bus.publish(MessageV2.Event.PartRemoved, {
sessionID: sessionID,
messageID: last.info.id,
partID: part.id,
})
}
}
await Session.update(sessionID, (draft) => {
draft.revert = undefined
})
}
}

View File

@@ -3,7 +3,7 @@ import path from "path"
import fs from "fs/promises"
import { Log } from "../util/log"
import { Global } from "../global"
import { z } from "zod"
import z from "zod/v4"
import { Config } from "../config/config"
import { Instance } from "../project/instance"
@@ -55,7 +55,15 @@ export namespace Snapshot {
export async function patch(hash: string): Promise<Patch> {
const git = gitdir()
await $`git --git-dir ${git} add .`.quiet().cwd(Instance.directory).nothrow()
const files = await $`git --git-dir ${git} diff --name-only ${hash} -- .`.cwd(Instance.directory).text()
const result = await $`git --git-dir ${git} diff --name-only ${hash} -- .`.quiet().cwd(Instance.directory).nothrow()
// If git diff fails, return empty patch
if (result.exitCode !== 0) {
log.warn("failed to get diff", { hash, exitCode: result.exitCode })
return { hash, files: [] }
}
const files = result.text()
return {
hash,
files: files
@@ -70,9 +78,19 @@ export namespace Snapshot {
export async function restore(snapshot: string) {
log.info("restore", { commit: snapshot })
const git = gitdir()
await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f`
const result = await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f`
.quiet()
.cwd(Instance.worktree)
.nothrow()
if (result.exitCode !== 0) {
log.error("failed to restore snapshot", {
snapshot,
exitCode: result.exitCode,
stderr: result.stderr.toString(),
stdout: result.stdout.toString(),
})
}
}
export async function revert(patches: Patch[]) {
@@ -97,8 +115,19 @@ export namespace Snapshot {
export async function diff(hash: string) {
const git = gitdir()
const result = await $`git --git-dir=${git} diff ${hash} -- .`.quiet().cwd(Instance.worktree).text()
return result.trim()
const result = await $`git --git-dir=${git} diff ${hash} -- .`.quiet().cwd(Instance.worktree).nothrow()
if (result.exitCode !== 0) {
log.warn("failed to get diff", {
hash,
exitCode: result.exitCode,
stderr: result.stderr.toString(),
stdout: result.stdout.toString(),
})
return ""
}
return result.text().trim()
}
function gitdir() {

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { exec } from "child_process"
import { Tool } from "./tool"
@@ -59,7 +59,7 @@ export const BashTool = Tool.define("bash", {
const tree = await parser().then((p) => p.parse(params.command))
const permissions = await Agent.get(ctx.agent).then((x) => x.permission.bash)
let needsAsk = false
const askPatterns = new Set<string>()
for (const node of tree.rootNode.descendantsOfType("command")) {
const command = []
for (let i = 0; i < node.childCount; i++) {
@@ -96,27 +96,52 @@ export const BashTool = Tool.define("bash", {
}
// always allow cd if it passes above check
if (!needsAsk && command[0] !== "cd") {
if (command[0] !== "cd") {
const action = Wildcard.all(node.text, permissions)
if (action === "deny") {
throw new Error(
`The user has specifically restricted access to this command, you are not allowed to execute it. Here is the configuration: ${JSON.stringify(permissions)}`,
)
}
if (action === "ask") needsAsk = true
if (action === "ask") {
const pattern = (() => {
let head = ""
let sub: string | undefined
for (let i = 0; i < node.childCount; i++) {
const child = node.child(i)
if (!child) continue
if (child.type === "command_name") {
if (!head) {
head = child.text
}
continue
}
if (!sub && child.type === "word") {
if (!child.text.startsWith("-")) sub = child.text
}
}
if (!head) return
return sub ? `${head} ${sub} *` : `${head} *`
})()
if (pattern) {
askPatterns.add(pattern)
}
}
}
}
if (needsAsk) {
if (askPatterns.size > 0) {
const patterns = Array.from(askPatterns)
await Permission.ask({
type: "bash",
pattern: params.command,
pattern: patterns,
sessionID: ctx.sessionID,
messageID: ctx.messageID,
callID: ctx.callID,
title: params.command,
metadata: {
command: params.command,
patterns,
},
})
}

View File

@@ -3,8 +3,8 @@ Executes a given bash command in a persistent shell session with optional timeou
Before executing the command, please follow these steps:
1. Directory Verification:
- If the command will create new directories or files, first use the LS tool to verify the parent directory exists and is the correct location
- For example, before running "mkdir foo/bar", first use LS to check that "foo" exists and is the intended parent directory
- If the command will create new directories or files, first use the List tool to verify the parent directory exists and is the correct location
- For example, before running "mkdir foo/bar", first use List to check that "foo" exists and is the intended parent directory
2. Command Execution:
- Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
@@ -21,7 +21,7 @@ Usage notes:
- You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 120000ms (2 minutes).
- It is very helpful if you write a clear, concise description of what this command does in 5-10 words.
- If the output exceeds 30000 characters, output will be truncated before being returned to you.
- VERY IMPORTANT: You MUST avoid using search commands like `find` and `grep`. Instead use Grep, Glob, or Task to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use Read and LS to read files.
- VERY IMPORTANT: You MUST avoid using search commands like `find` and `grep`. Instead use Grep, Glob, or Task to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use Read and List to read files.
- If you _still_ need to run `grep`, STOP. ALWAYS USE ripgrep at `rg` (or /usr/bin/rg) first, which all opencode users have pre-installed.
- When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings).
- Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of `cd`. You may use `cd` if the User explicitly requests it.

View File

@@ -3,7 +3,7 @@
// https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/utils/editCorrector.ts
// https://github.com/cline/cline/blob/main/evals/diff-edits/diff-apply/diff-06-26-25.ts
import { z } from "zod"
import z from "zod/v4"
import * as path from "path"
import { Tool } from "./tool"
import { LSP } from "../lsp"
@@ -82,7 +82,6 @@ export const EditTool = Tool.define("edit", {
sessionID: ctx.sessionID,
messageID: ctx.messageID,
callID: ctx.callID,
pattern: filePath,
title: "Edit this file: " + filePath,
metadata: {
filePath,

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import path from "path"
import { Tool } from "./tool"
import DESCRIPTION from "./glob.txt"

View File

@@ -2,5 +2,5 @@
- Supports glob patterns like "**/*.js" or "src/**/*.ts"
- Returns matching file paths sorted by modification time
- Use this tool when you need to find files by name patterns
- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead
- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Task tool instead
- You have the capability to call multiple tools in a single response. It is always better to speculatively perform multiple searches as a batch that are potentially useful.

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import { Ripgrep } from "../file/ripgrep"

View File

@@ -5,4 +5,4 @@
- Returns file paths with at least one match sorted by modification time
- Use this tool when you need to find files containing specific patterns
- If you need to identify/count the number of matches within files, use the Bash tool with `rg` (ripgrep) directly. Do NOT use `grep`.
- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead
- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Task tool instead

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
export const InvalidTool = Tool.define("invalid", {

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import * as path from "path"
import DESCRIPTION from "./ls.txt"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import path from "path"
import { LSP } from "../lsp"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import path from "path"
import { LSP } from "../lsp"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import { EditTool } from "./edit"
import DESCRIPTION from "./multiedit.txt"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import * as path from "path"
import * as fs from "fs/promises"
import { Tool } from "./tool"

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import * as fs from "fs"
import * as path from "path"
import { Tool } from "./tool"

View File

@@ -1,4 +1,4 @@
import z from "zod"
import z from "zod/v4"
import { BashTool } from "./bash"
import { EditTool } from "./edit"
import { GlobTool } from "./glob"
@@ -124,35 +124,13 @@ export namespace ToolRegistry {
return allTools().map((t) => t.id)
}
export async function tools(providerID: string, _modelID: string) {
export async function tools(_providerID: string, _modelID: string) {
const result = await Promise.all(
allTools().map(async (t) => ({
id: t.id,
...(await t.init()),
})),
)
if (providerID === "openai") {
return result.map((t) => ({
...t,
parameters: optionalToNullable(t.parameters as unknown as z.ZodTypeAny),
}))
}
if (providerID === "azure") {
return result.map((t) => ({
...t,
parameters: optionalToNullable(t.parameters as unknown as z.ZodTypeAny),
}))
}
if (providerID === "google") {
return result.map((t) => ({
...t,
parameters: sanitizeGeminiParameters(t.parameters as unknown as z.ZodTypeAny),
}))
}
return result
}
@@ -178,93 +156,4 @@ export namespace ToolRegistry {
return result
}
function sanitizeGeminiParameters(schema: z.ZodTypeAny, visited = new Set()): z.ZodTypeAny {
if (!schema || visited.has(schema)) {
return schema
}
visited.add(schema)
if (schema instanceof z.ZodDefault) {
const innerSchema = schema.removeDefault()
// Handle Gemini's incompatibility with `default` on `anyOf` (unions).
if (innerSchema instanceof z.ZodUnion) {
// The schema was `z.union(...).default(...)`, which is not allowed.
// We strip the default and return the sanitized union.
return sanitizeGeminiParameters(innerSchema, visited)
}
// Otherwise, the default is on a regular type, which is allowed.
// We recurse on the inner type and then re-apply the default.
return sanitizeGeminiParameters(innerSchema, visited).default(schema._def.defaultValue())
}
if (schema instanceof z.ZodOptional) {
return z.optional(sanitizeGeminiParameters(schema.unwrap(), visited))
}
if (schema instanceof z.ZodObject) {
const newShape: Record<string, z.ZodTypeAny> = {}
for (const [key, value] of Object.entries(schema.shape)) {
newShape[key] = sanitizeGeminiParameters(value as z.ZodTypeAny, visited)
}
return z.object(newShape)
}
if (schema instanceof z.ZodArray) {
return z.array(sanitizeGeminiParameters(schema.element, visited))
}
if (schema instanceof z.ZodUnion) {
// This schema corresponds to `anyOf` in JSON Schema.
// We recursively sanitize each option in the union.
const sanitizedOptions = schema.options.map((option: z.ZodTypeAny) => sanitizeGeminiParameters(option, visited))
return z.union(sanitizedOptions as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]])
}
if (schema instanceof z.ZodString) {
const newSchema = z.string({ description: schema.description })
const safeChecks = ["min", "max", "length", "regex", "startsWith", "endsWith", "includes", "trim"]
// rome-ignore lint/suspicious/noExplicitAny: <explanation>
;(newSchema._def as any).checks = (schema._def as z.ZodStringDef).checks.filter((check) =>
safeChecks.includes(check.kind),
)
return newSchema
}
return schema
}
function optionalToNullable(schema: z.ZodTypeAny): z.ZodTypeAny {
if (schema instanceof z.ZodObject) {
const shape = schema.shape
const newShape: Record<string, z.ZodTypeAny> = {}
for (const [key, value] of Object.entries(shape)) {
const zodValue = value as z.ZodTypeAny
if (zodValue instanceof z.ZodOptional) {
newShape[key] = zodValue.unwrap().nullable()
} else {
newShape[key] = optionalToNullable(zodValue)
}
}
return z.object(newShape)
}
if (schema instanceof z.ZodArray) {
return z.array(optionalToNullable(schema.element))
}
if (schema instanceof z.ZodUnion) {
return z.union(
schema.options.map((option: z.ZodTypeAny) => optionalToNullable(option)) as [
z.ZodTypeAny,
z.ZodTypeAny,
...z.ZodTypeAny[],
],
)
}
return schema
}
}

View File

@@ -1,11 +1,12 @@
import { Tool } from "./tool"
import DESCRIPTION from "./task.txt"
import { z } from "zod"
import z from "zod/v4"
import { Session } from "../session"
import { Bus } from "../bus"
import { MessageV2 } from "../session/message-v2"
import { Identifier } from "../id/id"
import { Agent } from "../agent/agent"
import { SessionPrompt } from "../session/prompt"
export const TaskTool = Tool.define("task", async () => {
const agents = await Agent.list().then((x) => x.filter((a) => a.mode !== "primary"))
@@ -49,9 +50,9 @@ export const TaskTool = Tool.define("task", async () => {
}
ctx.abort.addEventListener("abort", () => {
Session.abort(session.id)
SessionPrompt.abort(session.id)
})
const result = await Session.prompt({
const result = await SessionPrompt.prompt({
messageID,
sessionID: session.id,
model: {

View File

@@ -5,13 +5,13 @@ Available agent types and the tools they have access to:
When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
When to use the Agent tool:
- When you are instructed to execute custom slash commands. Use the Agent tool with the slash command invocation as the entire prompt. The slash command can take arguments. For example: Task(description="Check the file", prompt="/check-file path/to/file.py")
When to use the Task tool:
- When you are instructed to execute custom slash commands. Use the Task tool with the slash command invocation as the entire prompt. The slash command can take arguments. For example: Task(description="Check the file", prompt="/check-file path/to/file.py")
When NOT to use the Agent tool:
- If you want to read a specific file path, use the Read or Glob tool instead of the Agent tool, to find the match more quickly
When NOT to use the Task tool:
- If you want to read a specific file path, use the Read or Glob tool instead of the Task tool, to find the match more quickly
- If you are searching for a specific class definition like "class Foo", use the Glob tool instead, to find the match more quickly
- If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Agent tool, to find the match more quickly
- If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Task tool, to find the match more quickly
- Other tasks that are not related to the agent descriptions above

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import DESCRIPTION_WRITE from "./todowrite.txt"
import { Instance } from "../project/instance"

View File

@@ -1,4 +1,4 @@
import type { StandardSchemaV1 } from "@standard-schema/spec"
import z from "zod/v4"
export namespace Tool {
interface Metadata {
@@ -13,13 +13,13 @@ export namespace Tool {
extra?: { [key: string]: any }
metadata(input: { title?: string; metadata?: M }): void
}
export interface Info<Parameters extends StandardSchemaV1 = StandardSchemaV1, M extends Metadata = Metadata> {
export interface Info<Parameters extends z.ZodType = z.ZodType, M extends Metadata = Metadata> {
id: string
init: () => Promise<{
description: string
parameters: Parameters
execute(
args: StandardSchemaV1.InferOutput<Parameters>,
args: z.infer<Parameters>,
ctx: Context,
): Promise<{
title: string
@@ -29,7 +29,7 @@ export namespace Tool {
}>
}
export function define<Parameters extends StandardSchemaV1, Result extends Metadata>(
export function define<Parameters extends z.ZodType, Result extends Metadata>(
id: string,
init: Info<Parameters, Result>["init"] | Awaited<ReturnType<Info<Parameters, Result>["init"]>>,
): Info<Parameters, Result> {

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import { Tool } from "./tool"
import TurndownService from "turndown"
import DESCRIPTION from "./webfetch.txt"
@@ -28,7 +28,6 @@ export const WebFetchTool = Tool.define("webfetch", {
if (cfg.permission?.webfetch === "ask")
await Permission.ask({
type: "webfetch",
pattern: params.url,
sessionID: ctx.sessionID,
messageID: ctx.messageID,
callID: ctx.callID,

View File

@@ -1,4 +1,4 @@
import { z } from "zod"
import z from "zod/v4"
import * as path from "path"
import { Tool } from "./tool"
import { LSP } from "../lsp"

View File

@@ -1,19 +1,19 @@
import { z, type ZodSchema } from "zod"
import z from "zod/v4"
// import { Log } from "./log"
// const log = Log.create()
export abstract class NamedError extends Error {
abstract schema(): ZodSchema
abstract schema(): z.core.$ZodType
abstract toObject(): { name: string; data: any }
static create<Name extends string, Data extends ZodSchema>(name: Name, data: Data) {
static create<Name extends string, Data extends z.core.$ZodType>(name: Name, data: Data) {
const schema = z
.object({
name: z.literal(name),
data,
})
.openapi({
.meta({
ref: name,
})
const result = class extends NamedError {

View File

@@ -1,10 +1,10 @@
import path from "path"
import fs from "fs/promises"
import { Global } from "../global"
import z from "zod"
import z from "zod/v4"
export namespace Log {
export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).openapi({ ref: "LogLevel", description: "Log level" })
export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" })
export type Level = z.infer<typeof Level>
const levelPriority: Record<Level, number> = {

View File

@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"
import { Session } from "../../src/session/index"
import { SessionPrompt } from "../../src/session/prompt"
describe("fileRegex", () => {
const template = `This is a @valid/path/to/a/file and it should also match at
@@ -23,7 +23,7 @@ as well as @~/home-files and @~/paths/under/home.txt.
If the reference is \`@quoted/in/backticks\` then it shouldn't match at all.`
const matches = Array.from(template.matchAll(Session.fileRegex))
const matches = Array.from(template.matchAll(SessionPrompt.fileRegex))
test("should extract exactly 12 file references", () => {
expect(matches.length).toBe(12)
@@ -79,13 +79,13 @@ If the reference is \`@quoted/in/backticks\` then it shouldn't match at all.`
test("should not match when preceded by backtick", () => {
const backtickTest = "This `@should/not/match` should be ignored"
const backtickMatches = Array.from(backtickTest.matchAll(Session.fileRegex))
const backtickMatches = Array.from(backtickTest.matchAll(SessionPrompt.fileRegex))
expect(backtickMatches.length).toBe(0)
})
test("should not match email addresses", () => {
const emailTest = "Contact user@example.com for help"
const emailMatches = Array.from(emailTest.matchAll(Session.fileRegex))
const emailMatches = Array.from(emailTest.matchAll(SessionPrompt.fileRegex))
expect(emailMatches.length).toBe(0)
})
})

View File

@@ -1,4 +1,3 @@
import "zod-openapi/extend"
import { describe, expect, test } from "bun:test"
import path from "path"
import os from "os"

View File

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

View File

@@ -1,3 +1,3 @@
{
".": "0.9.0"
".": "0.13.0"
}

View File

@@ -1,4 +1,4 @@
configured_endpoints: 43
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-46826ba8640557721614b0c9a3f1860681d825ca8d8b12869652fa25aacb0b4c.yml
openapi_spec_hash: 33b8db6fde3021579b21325ce910197d
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-2e754dafcad0636137256cef499b2bcd72cf17de08f44ec03c3589b2a05341a2.yml
openapi_spec_hash: 2d3cf84d3033068ce6c07386411527ef
config_hash: 026ef000d34bf2f930e7b41e77d2d3ff

View File

@@ -1,5 +1,37 @@
# Changelog
## 0.13.0 (2025-09-14)
Full Changelog: [v0.12.0...v0.13.0](https://github.com/sst/opencode-sdk-go/compare/v0.12.0...v0.13.0)
### Features
- **api:** api update ([80da4fb](https://github.com/sst/opencode-sdk-go/commit/80da4fb4ea9c6afb51a7e7135d9f5560ce6f2a6c))
## 0.12.0 (2025-09-14)
Full Changelog: [v0.11.0...v0.12.0](https://github.com/sst/opencode-sdk-go/compare/v0.11.0...v0.12.0)
### Features
- **api:** api update ([7e3808b](https://github.com/sst/opencode-sdk-go/commit/7e3808ba349dc653174b32b48a1120c18d2975c2))
## 0.11.0 (2025-09-14)
Full Changelog: [v0.10.0...v0.11.0](https://github.com/sst/opencode-sdk-go/compare/v0.10.0...v0.11.0)
### Features
- **api:** api update ([a3d37f5](https://github.com/sst/opencode-sdk-go/commit/a3d37f5671545866547d351fc21b49809cc8b3c2))
## 0.10.0 (2025-09-11)
Full Changelog: [v0.9.0...v0.10.0](https://github.com/sst/opencode-sdk-go/compare/v0.9.0...v0.10.0)
### Features
- **api:** api update ([0dc01f6](https://github.com/sst/opencode-sdk-go/commit/0dc01f6695c9b8400a4dc92166c5002bb120cf50))
## 0.9.0 (2025-09-10)
Full Changelog: [v0.8.0...v0.9.0](https://github.com/sst/opencode-sdk-go/compare/v0.8.0...v0.9.0)

View File

@@ -24,7 +24,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->
```sh
go get -u 'github.com/sst/opencode-sdk-go@v0.9.0'
go get -u 'github.com/sst/opencode-sdk-go@v0.13.0'
```
<!-- x-release-please-end -->

View File

@@ -12,6 +12,9 @@ type Error = apierror.Error
// This is an alias to an internal type.
type MessageAbortedError = shared.MessageAbortedError
// This is an alias to an internal type.
type MessageAbortedErrorData = shared.MessageAbortedErrorData
// This is an alias to an internal type.
type MessageAbortedErrorName = shared.MessageAbortedErrorName

View File

@@ -47,6 +47,7 @@ type Command struct {
Agent string `json:"agent"`
Description string `json:"description"`
Model string `json:"model"`
Subtask bool `json:"subtask"`
JSON commandJSON `json:"-"`
}
@@ -57,6 +58,7 @@ type commandJSON struct {
Agent apijson.Field
Description apijson.Field
Model apijson.Field
Subtask apijson.Field
raw string
ExtraFields map[string]apijson.Field
}

View File

@@ -676,6 +676,7 @@ type ConfigCommand struct {
Agent string `json:"agent"`
Description string `json:"description"`
Model string `json:"model"`
Subtask bool `json:"subtask"`
JSON configCommandJSON `json:"-"`
}
@@ -685,6 +686,7 @@ type configCommandJSON struct {
Agent apijson.Field
Description apijson.Field
Model apijson.Field
Subtask apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
@@ -698,18 +700,18 @@ func (r configCommandJSON) RawJSON() string {
}
type ConfigExperimental struct {
Hook ConfigExperimentalHook `json:"hook"`
DisablePasteSummary bool `json:"disable_paste_summary"`
Hook ConfigExperimentalHook `json:"hook"`
JSON configExperimentalJSON `json:"-"`
}
// configExperimentalJSON contains the JSON metadata for the struct
// [ConfigExperimental]
type configExperimentalJSON struct {
Hook apijson.Field
SummarizePaste apijson.Field
raw string
ExtraFields map[string]apijson.Field
DisablePasteSummary apijson.Field
Hook apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ConfigExperimental) UnmarshalJSON(data []byte) (err error) {
@@ -1022,16 +1024,14 @@ type ConfigMcpUnion interface {
func init() {
apijson.RegisterUnion(
reflect.TypeOf((*ConfigMcpUnion)(nil)).Elem(),
"type",
"",
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(McpLocalConfig{}),
DiscriminatorValue: "local",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(McpLocalConfig{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(McpRemoteConfig{}),
DiscriminatorValue: "remote",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(McpRemoteConfig{}),
},
)
}
@@ -1753,15 +1753,15 @@ func (r ConfigShare) IsKnown() bool {
// TUI specific settings
type ConfigTui struct {
// TUI scroll speed
ScrollSpeed float64 `json:"scroll_speed,required"`
JSON configTuiJSON `json:"-"`
ScrollSpeed float64 `json:"scroll_speed"`
JSON configTuiJSON `json:"-"`
}
// configTuiJSON contains the JSON metadata for the struct [ConfigTui]
type configTuiJSON struct {
ScrollSpeed apijson.Field
raw string
ExtraFields map[string]apijson.Field
ScrollSpeed apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ConfigTui) UnmarshalJSON(data []byte) (err error) {
@@ -1772,105 +1772,106 @@ func (r configTuiJSON) RawJSON() string {
return r.raw
}
// Custom keybind configurations
type KeybindsConfig struct {
// Next agent
AgentCycle string `json:"agent_cycle,required"`
AgentCycle string `json:"agent_cycle"`
// Previous agent
AgentCycleReverse string `json:"agent_cycle_reverse,required"`
AgentCycleReverse string `json:"agent_cycle_reverse"`
// List agents
AgentList string `json:"agent_list,required"`
AgentList string `json:"agent_list"`
// Exit the application
AppExit string `json:"app_exit,required"`
AppExit string `json:"app_exit"`
// Show help dialog
AppHelp string `json:"app_help,required"`
AppHelp string `json:"app_help"`
// Open external editor
EditorOpen string `json:"editor_open,required"`
EditorOpen string `json:"editor_open"`
// @deprecated Close file
FileClose string `json:"file_close,required"`
FileClose string `json:"file_close"`
// @deprecated Split/unified diff
FileDiffToggle string `json:"file_diff_toggle,required"`
FileDiffToggle string `json:"file_diff_toggle"`
// @deprecated Currently not available. List files
FileList string `json:"file_list,required"`
FileList string `json:"file_list"`
// @deprecated Search file
FileSearch string `json:"file_search,required"`
FileSearch string `json:"file_search"`
// Clear input field
InputClear string `json:"input_clear,required"`
InputClear string `json:"input_clear"`
// Insert newline in input
InputNewline string `json:"input_newline,required"`
InputNewline string `json:"input_newline"`
// Paste from clipboard
InputPaste string `json:"input_paste,required"`
InputPaste string `json:"input_paste"`
// Submit input
InputSubmit string `json:"input_submit,required"`
InputSubmit string `json:"input_submit"`
// Leader key for keybind combinations
Leader string `json:"leader,required"`
Leader string `json:"leader"`
// Copy message
MessagesCopy string `json:"messages_copy,required"`
MessagesCopy string `json:"messages_copy"`
// Navigate to first message
MessagesFirst string `json:"messages_first,required"`
MessagesFirst string `json:"messages_first"`
// Scroll messages down by half page
MessagesHalfPageDown string `json:"messages_half_page_down,required"`
MessagesHalfPageDown string `json:"messages_half_page_down"`
// Scroll messages up by half page
MessagesHalfPageUp string `json:"messages_half_page_up,required"`
MessagesHalfPageUp string `json:"messages_half_page_up"`
// Navigate to last message
MessagesLast string `json:"messages_last,required"`
MessagesLast string `json:"messages_last"`
// @deprecated Toggle layout
MessagesLayoutToggle string `json:"messages_layout_toggle,required"`
MessagesLayoutToggle string `json:"messages_layout_toggle"`
// @deprecated Navigate to next message
MessagesNext string `json:"messages_next,required"`
MessagesNext string `json:"messages_next"`
// Scroll messages down by one page
MessagesPageDown string `json:"messages_page_down,required"`
MessagesPageDown string `json:"messages_page_down"`
// Scroll messages up by one page
MessagesPageUp string `json:"messages_page_up,required"`
MessagesPageUp string `json:"messages_page_up"`
// @deprecated Navigate to previous message
MessagesPrevious string `json:"messages_previous,required"`
MessagesPrevious string `json:"messages_previous"`
// Redo message
MessagesRedo string `json:"messages_redo,required"`
MessagesRedo string `json:"messages_redo"`
// @deprecated use messages_undo. Revert message
MessagesRevert string `json:"messages_revert,required"`
MessagesRevert string `json:"messages_revert"`
// Undo message
MessagesUndo string `json:"messages_undo,required"`
MessagesUndo string `json:"messages_undo"`
// Next recent model
ModelCycleRecent string `json:"model_cycle_recent,required"`
ModelCycleRecent string `json:"model_cycle_recent"`
// Previous recent model
ModelCycleRecentReverse string `json:"model_cycle_recent_reverse,required"`
ModelCycleRecentReverse string `json:"model_cycle_recent_reverse"`
// List available models
ModelList string `json:"model_list,required"`
ModelList string `json:"model_list"`
// Create/update AGENTS.md
ProjectInit string `json:"project_init,required"`
ProjectInit string `json:"project_init"`
// Cycle to next child session
SessionChildCycle string `json:"session_child_cycle,required"`
SessionChildCycle string `json:"session_child_cycle"`
// Cycle to previous child session
SessionChildCycleReverse string `json:"session_child_cycle_reverse,required"`
SessionChildCycleReverse string `json:"session_child_cycle_reverse"`
// Compact the session
SessionCompact string `json:"session_compact,required"`
SessionCompact string `json:"session_compact"`
// Export session to editor
SessionExport string `json:"session_export,required"`
SessionExport string `json:"session_export"`
// Interrupt current session
SessionInterrupt string `json:"session_interrupt,required"`
SessionInterrupt string `json:"session_interrupt"`
// List all sessions
SessionList string `json:"session_list,required"`
SessionList string `json:"session_list"`
// Create a new session
SessionNew string `json:"session_new,required"`
SessionNew string `json:"session_new"`
// Share current session
SessionShare string `json:"session_share,required"`
SessionShare string `json:"session_share"`
// Show session timeline
SessionTimeline string `json:"session_timeline,required"`
SessionTimeline string `json:"session_timeline"`
// Unshare current session
SessionUnshare string `json:"session_unshare,required"`
SessionUnshare string `json:"session_unshare"`
// @deprecated use agent_cycle. Next agent
SwitchAgent string `json:"switch_agent,required"`
SwitchAgent string `json:"switch_agent"`
// @deprecated use agent_cycle_reverse. Previous agent
SwitchAgentReverse string `json:"switch_agent_reverse,required"`
SwitchAgentReverse string `json:"switch_agent_reverse"`
// @deprecated use agent_cycle. Next mode
SwitchMode string `json:"switch_mode,required"`
SwitchMode string `json:"switch_mode"`
// @deprecated use agent_cycle_reverse. Previous mode
SwitchModeReverse string `json:"switch_mode_reverse,required"`
SwitchModeReverse string `json:"switch_mode_reverse"`
// List available themes
ThemeList string `json:"theme_list,required"`
ThemeList string `json:"theme_list"`
// Toggle thinking blocks
ThinkingBlocks string `json:"thinking_blocks,required"`
ThinkingBlocks string `json:"thinking_blocks"`
// Toggle tool details
ToolDetails string `json:"tool_details,required"`
ToolDetails string `json:"tool_details"`
JSON keybindsConfigJSON `json:"-"`
}

View File

@@ -57,14 +57,14 @@ type EventListResponse struct {
// [EventListResponseEventMessageUpdatedProperties],
// [EventListResponseEventMessageRemovedProperties],
// [EventListResponseEventMessagePartUpdatedProperties],
// [EventListResponseEventMessagePartRemovedProperties], [Permission],
// [EventListResponseEventMessagePartRemovedProperties],
// [EventListResponseEventSessionCompactedProperties], [Permission],
// [EventListResponseEventPermissionRepliedProperties],
// [EventListResponseEventFileEditedProperties],
// [EventListResponseEventSessionIdleProperties],
// [EventListResponseEventSessionUpdatedProperties],
// [EventListResponseEventSessionDeletedProperties],
// [EventListResponseEventSessionIdleProperties],
// [EventListResponseEventSessionErrorProperties],
// [EventListResponseEventSessionCompactedProperties], [interface{}].
// [EventListResponseEventSessionErrorProperties], [interface{}].
Properties interface{} `json:"properties,required"`
Type EventListResponseType `json:"type,required"`
JSON eventListResponseJSON `json:"-"`
@@ -102,11 +102,11 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
// [EventListResponseEventMessagePartUpdated],
// [EventListResponseEventMessagePartRemoved],
// [EventListResponseEventSessionCompacted],
// [EventListResponseEventPermissionUpdated],
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
// [EventListResponseEventSessionCompacted],
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionUpdated],
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError],
// [EventListResponseEventServerConnected].
func (r EventListResponse) AsUnion() EventListResponseUnion {
return r.union
@@ -117,11 +117,11 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
// [EventListResponseEventMessagePartUpdated],
// [EventListResponseEventMessagePartRemoved],
// [EventListResponseEventSessionCompacted],
// [EventListResponseEventPermissionUpdated],
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
// [EventListResponseEventSessionCompacted] or
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionUpdated],
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError] or
// [EventListResponseEventServerConnected].
type EventListResponseUnion interface {
implementsEventListResponse()
@@ -130,81 +130,66 @@ type EventListResponseUnion interface {
func init() {
apijson.RegisterUnion(
reflect.TypeOf((*EventListResponseUnion)(nil)).Elem(),
"type",
"",
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventInstallationUpdated{}),
DiscriminatorValue: "installation.updated",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventInstallationUpdated{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventLspClientDiagnostics{}),
DiscriminatorValue: "lsp.client.diagnostics",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventLspClientDiagnostics{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessageUpdated{}),
DiscriminatorValue: "message.updated",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessageUpdated{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessageRemoved{}),
DiscriminatorValue: "message.removed",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessageRemoved{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessagePartUpdated{}),
DiscriminatorValue: "message.part.updated",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessagePartUpdated{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessagePartRemoved{}),
DiscriminatorValue: "message.part.removed",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventMessagePartRemoved{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
DiscriminatorValue: "permission.updated",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionCompacted{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
DiscriminatorValue: "permission.replied",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
DiscriminatorValue: "file.edited",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}),
DiscriminatorValue: "session.updated",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionDeleted{}),
DiscriminatorValue: "session.deleted",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionIdle{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionIdle{}),
DiscriminatorValue: "session.idle",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionError{}),
DiscriminatorValue: "session.error",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionDeleted{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionCompacted{}),
DiscriminatorValue: "session.compacted",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionError{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
DiscriminatorValue: "server.connected",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
},
)
}
@@ -577,6 +562,66 @@ func (r EventListResponseEventMessagePartRemovedType) IsKnown() bool {
return false
}
type EventListResponseEventSessionCompacted struct {
Properties EventListResponseEventSessionCompactedProperties `json:"properties,required"`
Type EventListResponseEventSessionCompactedType `json:"type,required"`
JSON eventListResponseEventSessionCompactedJSON `json:"-"`
}
// eventListResponseEventSessionCompactedJSON contains the JSON metadata for the
// struct [EventListResponseEventSessionCompacted]
type eventListResponseEventSessionCompactedJSON struct {
Properties apijson.Field
Type apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionCompacted) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionCompactedJSON) RawJSON() string {
return r.raw
}
func (r EventListResponseEventSessionCompacted) implementsEventListResponse() {}
type EventListResponseEventSessionCompactedProperties struct {
SessionID string `json:"sessionID,required"`
JSON eventListResponseEventSessionCompactedPropertiesJSON `json:"-"`
}
// eventListResponseEventSessionCompactedPropertiesJSON contains the JSON metadata
// for the struct [EventListResponseEventSessionCompactedProperties]
type eventListResponseEventSessionCompactedPropertiesJSON struct {
SessionID apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionCompactedProperties) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionCompactedPropertiesJSON) RawJSON() string {
return r.raw
}
type EventListResponseEventSessionCompactedType string
const (
EventListResponseEventSessionCompactedTypeSessionCompacted EventListResponseEventSessionCompactedType = "session.compacted"
)
func (r EventListResponseEventSessionCompactedType) IsKnown() bool {
switch r {
case EventListResponseEventSessionCompactedTypeSessionCompacted:
return true
}
return false
}
type EventListResponseEventPermissionUpdated struct {
Properties Permission `json:"properties,required"`
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
@@ -740,6 +785,66 @@ func (r EventListResponseEventFileEditedType) IsKnown() bool {
return false
}
type EventListResponseEventSessionIdle struct {
Properties EventListResponseEventSessionIdleProperties `json:"properties,required"`
Type EventListResponseEventSessionIdleType `json:"type,required"`
JSON eventListResponseEventSessionIdleJSON `json:"-"`
}
// eventListResponseEventSessionIdleJSON contains the JSON metadata for the struct
// [EventListResponseEventSessionIdle]
type eventListResponseEventSessionIdleJSON struct {
Properties apijson.Field
Type apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionIdle) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionIdleJSON) RawJSON() string {
return r.raw
}
func (r EventListResponseEventSessionIdle) implementsEventListResponse() {}
type EventListResponseEventSessionIdleProperties struct {
SessionID string `json:"sessionID,required"`
JSON eventListResponseEventSessionIdlePropertiesJSON `json:"-"`
}
// eventListResponseEventSessionIdlePropertiesJSON contains the JSON metadata for
// the struct [EventListResponseEventSessionIdleProperties]
type eventListResponseEventSessionIdlePropertiesJSON struct {
SessionID apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionIdleProperties) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionIdlePropertiesJSON) RawJSON() string {
return r.raw
}
type EventListResponseEventSessionIdleType string
const (
EventListResponseEventSessionIdleTypeSessionIdle EventListResponseEventSessionIdleType = "session.idle"
)
func (r EventListResponseEventSessionIdleType) IsKnown() bool {
switch r {
case EventListResponseEventSessionIdleTypeSessionIdle:
return true
}
return false
}
type EventListResponseEventSessionUpdated struct {
Properties EventListResponseEventSessionUpdatedProperties `json:"properties,required"`
Type EventListResponseEventSessionUpdatedType `json:"type,required"`
@@ -860,66 +965,6 @@ func (r EventListResponseEventSessionDeletedType) IsKnown() bool {
return false
}
type EventListResponseEventSessionIdle struct {
Properties EventListResponseEventSessionIdleProperties `json:"properties,required"`
Type EventListResponseEventSessionIdleType `json:"type,required"`
JSON eventListResponseEventSessionIdleJSON `json:"-"`
}
// eventListResponseEventSessionIdleJSON contains the JSON metadata for the struct
// [EventListResponseEventSessionIdle]
type eventListResponseEventSessionIdleJSON struct {
Properties apijson.Field
Type apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionIdle) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionIdleJSON) RawJSON() string {
return r.raw
}
func (r EventListResponseEventSessionIdle) implementsEventListResponse() {}
type EventListResponseEventSessionIdleProperties struct {
SessionID string `json:"sessionID,required"`
JSON eventListResponseEventSessionIdlePropertiesJSON `json:"-"`
}
// eventListResponseEventSessionIdlePropertiesJSON contains the JSON metadata for
// the struct [EventListResponseEventSessionIdleProperties]
type eventListResponseEventSessionIdlePropertiesJSON struct {
SessionID apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionIdleProperties) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionIdlePropertiesJSON) RawJSON() string {
return r.raw
}
type EventListResponseEventSessionIdleType string
const (
EventListResponseEventSessionIdleTypeSessionIdle EventListResponseEventSessionIdleType = "session.idle"
)
func (r EventListResponseEventSessionIdleType) IsKnown() bool {
switch r {
case EventListResponseEventSessionIdleTypeSessionIdle:
return true
}
return false
}
type EventListResponseEventSessionError struct {
Properties EventListResponseEventSessionErrorProperties `json:"properties,required"`
Type EventListResponseEventSessionErrorType `json:"type,required"`
@@ -970,7 +1015,7 @@ func (r eventListResponseEventSessionErrorPropertiesJSON) RawJSON() string {
type EventListResponseEventSessionErrorPropertiesError struct {
// This field can have the runtime type of [shared.ProviderAuthErrorData],
// [shared.UnknownErrorData], [interface{}].
// [shared.UnknownErrorData], [interface{}], [shared.MessageAbortedErrorData].
Data interface{} `json:"data,required"`
Name EventListResponseEventSessionErrorPropertiesErrorName `json:"name,required"`
JSON eventListResponseEventSessionErrorPropertiesErrorJSON `json:"-"`
@@ -1020,26 +1065,22 @@ type EventListResponseEventSessionErrorPropertiesErrorUnion interface {
func init() {
apijson.RegisterUnion(
reflect.TypeOf((*EventListResponseEventSessionErrorPropertiesErrorUnion)(nil)).Elem(),
"name",
"",
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(shared.ProviderAuthError{}),
DiscriminatorValue: "ProviderAuthError",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(shared.ProviderAuthError{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(shared.UnknownError{}),
DiscriminatorValue: "UnknownError",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(shared.UnknownError{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionErrorPropertiesErrorMessageOutputLengthError{}),
DiscriminatorValue: "MessageOutputLengthError",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventSessionErrorPropertiesErrorMessageOutputLengthError{}),
},
apijson.UnionVariant{
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(shared.MessageAbortedError{}),
DiscriminatorValue: "MessageAbortedError",
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(shared.MessageAbortedError{}),
},
)
}
@@ -1116,66 +1157,6 @@ func (r EventListResponseEventSessionErrorType) IsKnown() bool {
return false
}
type EventListResponseEventSessionCompacted struct {
Properties EventListResponseEventSessionCompactedProperties `json:"properties,required"`
Type EventListResponseEventSessionCompactedType `json:"type,required"`
JSON eventListResponseEventSessionCompactedJSON `json:"-"`
}
// eventListResponseEventSessionCompactedJSON contains the JSON metadata for the
// struct [EventListResponseEventSessionCompacted]
type eventListResponseEventSessionCompactedJSON struct {
Properties apijson.Field
Type apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionCompacted) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionCompactedJSON) RawJSON() string {
return r.raw
}
func (r EventListResponseEventSessionCompacted) implementsEventListResponse() {}
type EventListResponseEventSessionCompactedProperties struct {
SessionID string `json:"sessionID,required"`
JSON eventListResponseEventSessionCompactedPropertiesJSON `json:"-"`
}
// eventListResponseEventSessionCompactedPropertiesJSON contains the JSON metadata
// for the struct [EventListResponseEventSessionCompactedProperties]
type eventListResponseEventSessionCompactedPropertiesJSON struct {
SessionID apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *EventListResponseEventSessionCompactedProperties) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r eventListResponseEventSessionCompactedPropertiesJSON) RawJSON() string {
return r.raw
}
type EventListResponseEventSessionCompactedType string
const (
EventListResponseEventSessionCompactedTypeSessionCompacted EventListResponseEventSessionCompactedType = "session.compacted"
)
func (r EventListResponseEventSessionCompactedType) IsKnown() bool {
switch r {
case EventListResponseEventSessionCompactedTypeSessionCompacted:
return true
}
return false
}
type EventListResponseEventServerConnected struct {
Properties interface{} `json:"properties,required"`
Type EventListResponseEventServerConnectedType `json:"type,required"`
@@ -1224,20 +1205,20 @@ const (
EventListResponseTypeMessageRemoved EventListResponseType = "message.removed"
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
EventListResponseTypeSessionCompacted EventListResponseType = "session.compacted"
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
EventListResponseTypeSessionError EventListResponseType = "session.error"
EventListResponseTypeSessionCompacted EventListResponseType = "session.compacted"
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
)
func (r EventListResponseType) IsKnown() bool {
switch r {
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeSessionCompacted, EventListResponseTypeServerConnected:
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeSessionCompacted, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionIdle, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionError, EventListResponseTypeServerConnected:
return true
}
return false

View File

@@ -2,4 +2,4 @@
package internal
const PackageVersion = "0.9.0" // x-release-please-version
const PackageVersion = "0.13.0" // x-release-please-version

Some files were not shown because too many files have changed in this diff Show More