Compare commits

...
Author SHA1 Message Date
rekram1-node 95dd0c5e0c chore: upgrade Effect to 4.0 stable 2026-10-02 01:46:49 +00:00
394 changed files with 5037 additions and 4745 deletions

No files matched your search

+21 -40
View File
@@ -194,7 +194,7 @@
"zod": "catalog:",
},
"peerDependencies": {
"effect": "4.0.0-rc.112",
"effect": "4.0.0",
"solid-js": ">=1.9.0",
},
"optionalPeers": [
@@ -406,6 +406,7 @@
"@types/node": "catalog:",
"@types/which": "3.0.4",
"drizzle-kit": "catalog:",
"fast-check": "4.9.0",
},
},
"packages/desktop": {
@@ -441,7 +442,7 @@
"electron-builder": "26.15.7",
"electron-vite": "6.0.0-beta.1",
"solid-js": "catalog:",
"typescript": "~5.6.2",
"typescript": "catalog:",
"vite": "8.2.2",
},
"optionalDependencies": {
@@ -555,7 +556,7 @@
"name": "@opencode/http-recorder",
"version": "2.0.21",
"dependencies": {
"@effect/platform-node-shared": "4.0.0-rc.112",
"@effect/platform-node-shared": "4.0.0",
},
"devDependencies": {
"@effect/platform-node": "catalog:",
@@ -1147,10 +1148,10 @@
"catalog": {
"@cloudflare/workers-types": "4.20251008.0",
"@corvu/drawer": "0.2.4",
"@effect/opentelemetry": "4.0.0-rc.112",
"@effect/platform-node": "4.0.0-rc.112",
"@effect/platform-node-shared": "4.0.0-rc.112",
"@effect/sql-sqlite-bun": "4.0.0-rc.112",
"@effect/opentelemetry": "4.0.0",
"@effect/platform-node": "4.0.0",
"@effect/platform-node-shared": "4.0.0",
"@effect/sql-sqlite-bun": "4.0.0",
"@hono/standard-validator": "0.2.0",
"@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.13",
@@ -1190,7 +1191,7 @@
"dompurify": "3.4.14",
"drizzle-kit": "1.0.0-rc.5-ab785fc",
"drizzle-orm": "1.0.0-rc.5-169397b",
"effect": "4.0.0-rc.112",
"effect": "4.0.0",
"fuzzysort": "3.1.0",
"get-east-asian-width": "1.6.0",
"hono": "4.10.7",
@@ -1209,7 +1210,7 @@
"sst": "4.13.1",
"string-width": "7.2.0",
"tailwindcss": "4.1.11",
"typescript": "5.8.2",
"typescript": "5.9.3",
"ulid": "3.0.1",
"vite": "7.3.6",
"vite-plugin-solid": "2.11.10",
@@ -1722,13 +1723,13 @@
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.12.0", "", {}, "sha512-mlUE+rZ8CatQekLhnaiN91Iemdd+e2gFKooGlnRB3oPTL3VghLfX24dx7HrzMNeC1JrIB/0kpsfyty3f5HNfxQ=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-vXVhqlcADHtmKlw2gIqRRlXFve4ms4JJ5ykAqzNe37QQ/5N5A5gJ9VOXkMBORHZC5O4gdHZwxhAzGZb0zvFf/Q=="],
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="],
"@effect/platform-node": ["@effect/platform-node@4.0.0", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0", "undici": "^8.11.2" }, "peerDependencies": { "effect": "^4.0.0", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/L+4MUbl8FejPKLHLROYSOebvHnfixkP8KiblSD/DE5uH5xENZBHaux4nH6XMnRP+lr8ajpEJFS8sUrmmxFJeQ=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.22.0" }, "peerDependencies": { "effect": "^4.0.0" } }, "sha512-VBXHJU9UXVZPdQGGDRjGXpo+TpOzRwZuMrdKAtIxi1qwcRftmacZ1zTgIrzBa0Z2RA2KVkoOecQUsTlt/nJZhw=="],
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-EqR8pWZo3VzedRvP6qo5HcfqNmFvSa+sQLWQl3oBMx2KY1FCc8NYjep79wYjNkW0qABnffrPUXCMTOncd1A+5g=="],
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0", "", { "peerDependencies": { "effect": "^4.0.0" } }, "sha512-tUDqqNq4lZMLQkp8YDQej2uuy8BBjmqfMXcJU/KOmrK/WWbzudC8oabZ1TEs1lLSuKzhBEPhnE0cRtAOYe05ew=="],
"@electron-internal/extract-zip": ["@electron-internal/extract-zip@1.0.5", "", {}, "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA=="],
@@ -2062,18 +2063,6 @@
"@motionone/utils": ["@motionone/utils@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw=="],
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="],
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="],
"@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="],
"@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="],
"@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="],
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="],
"@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q=="],
@@ -3912,7 +3901,7 @@
"editorconfig": ["editorconfig@1.0.7", "", { "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw=="],
"effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="],
"effect": ["effect@4.0.0", "", {}, "sha512-ooc1TG5t+FfzgYnFz2ff6BBKyZ7EwBRVXC7c4RhQUAD6/TZ2gTXXMeb4WX7a19ozQo4J73/QW+S00YAIresoMQ=="],
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
@@ -4750,7 +4739,7 @@
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="],
"mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
@@ -4798,10 +4787,6 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"msgpackr": ["msgpackr@2.0.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA=="],
"msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="],
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
@@ -4844,8 +4829,6 @@
"node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
"node-html-parser": ["node-html-parser@7.1.0", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ=="],
"node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="],
@@ -5628,7 +5611,7 @@
"typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="],
@@ -5642,7 +5625,7 @@
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
"undici": ["undici@8.10.0", "", {}, "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ=="],
"undici": ["undici@8.11.2", "", {}, "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
@@ -6094,15 +6077,13 @@
"@bufbuild/protoplugin/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="],
"@cloudflare/kv-asset-handler/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"@cloudflare/vite-plugin/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
"@cloudflare/vite-plugin/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
"@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
"@effect/platform-node-shared/ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="],
"@effect/platform-node-shared/ws": ["ws@8.22.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg=="],
"@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
@@ -6234,8 +6215,6 @@
"@opencode/console-support/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
"@opencode/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
"@opencode/enterprise/@tailwindcss/vite": ["@tailwindcss/vite@4.1.11", "", { "dependencies": { "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "tailwindcss": "4.1.11" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw=="],
"@opencode/enterprise/tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
@@ -6694,6 +6673,8 @@
"tw-to-css/tailwindcss": ["tailwindcss@3.3.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w=="],
"unifont/undici": ["undici@8.10.0", "", {}, "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ=="],
"unplugin/acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="],
"unused-filename/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
+6 -6
View File
@@ -42,10 +42,10 @@
"packages/stats/*"
],
"catalog": {
"@effect/opentelemetry": "4.0.0-rc.112",
"@effect/platform-node": "4.0.0-rc.112",
"@effect/platform-node-shared": "4.0.0-rc.112",
"@effect/sql-sqlite-bun": "4.0.0-rc.112",
"@effect/opentelemetry": "4.0.0",
"@effect/platform-node": "4.0.0",
"@effect/platform-node-shared": "4.0.0",
"@effect/sql-sqlite-bun": "4.0.0",
"@npmcli/arborist": "9.4.0",
"@types/bun": "1.4.0",
"@types/cross-spawn": "6.0.6",
@@ -79,7 +79,7 @@
"dompurify": "3.4.14",
"drizzle-kit": "1.0.0-rc.5-ab785fc",
"drizzle-orm": "1.0.0-rc.5-169397b",
"effect": "4.0.0-rc.112",
"effect": "4.0.0",
"ai": "6.0.168",
"cross-spawn": "7.0.6",
"hono": "4.10.7",
@@ -92,7 +92,7 @@
"remend": "1.3.1",
"@playwright/test": "1.59.1",
"semver": "7.7.4",
"typescript": "5.8.2",
"typescript": "5.9.3",
"@typescript/native-preview": "7.0.0-dev.20251207.1",
"zod": "4.1.8",
"remeda": "2.26.0",
+1 -1
View File
@@ -15,7 +15,7 @@ import { OpenAI } from "@opencode/ai/providers"
* hover imports and local values to see how the public API is typed.
*/
const apiKey = Config.redacted("OPENAI_API_KEY")
const apiKey = Config.Redacted("OPENAI_API_KEY")
// 1. Configure a provider. The configured facade records provider identity,
// deployment options, authentication, and defaults. Per-modality selectors pick
+2 -2
View File
@@ -5,7 +5,7 @@ import * as path from "node:path"
import * as prompts from "@clack/prompts"
import { AwsV4Signer } from "aws4fetch"
import { Config, ConfigProvider, Effect, FileSystem, PlatformError, Redacted } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest, type HttpClientResponse } from "effect/unstable/http"
import { FetchHttpClient, HttpClient, HttpClientRequest, type HttpClientResponse } from "effect/http"
import * as ProviderShared from "../src/protocols/shared"
import { CloudflareAIGateway } from "../src/providers/cloudflare-ai-gateway.js"
import { CloudflareWorkersAI } from "../src/providers/cloudflare-workers-ai.js"
@@ -383,7 +383,7 @@ const readEnvFile = Effect.fn("RecordingEnv.readFile")(function* () {
})
const readConfigString = (provider: ConfigProvider.ConfigProvider, name: string) =>
Config.string(name)
Config.String(name)
.parse(provider)
.pipe(
Effect.match({
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientRequest } from "effect/http"
import {
ChoiceQuestion,
EvaluationInput,
+2 -1
View File
@@ -1,4 +1,5 @@
import { Effect, Schema, Stream } from "effect"
import { extendSchema } from "@opencode/schema/schema"
import { Generation, ProgressEvent, QueuedEvent, type AwaitOptions } from "./generation.js"
import { Media } from "./media.js"
import { MediaModel, composeRoute, tryRequest } from "./media-model.js"
@@ -142,7 +143,7 @@ const imageEventTagged = Schema.Union([
ImageOutputEvent,
ImageFinishEvent,
]).pipe(Schema.toTaggedUnion("type"))
export const ImageEvent = Object.assign(imageEventTagged, {
export const ImageEvent = extendSchema(imageEventTagged, {
is: {
generationQueued: imageEventTagged.guards["generation-queued"],
generationProgress: imageEventTagged.guards["generation-progress"],
+7 -6
View File
@@ -1,7 +1,8 @@
export * as Media from "./media.js"
import { Effect, Encoding, FileSystem, Schema, SchemaGetter } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { Effect, FileSystem, Schema, SchemaGetter } from "effect"
import { Base64 } from "effect/encoding"
import { HttpClientRequest } from "effect/http"
import { ProviderID } from "./schema/ids.js"
import { AIError, HttpContext, InvalidProviderOutputError, InvalidRequestError } from "./schema/errors.js"
import { ProviderMetadata } from "./schema/options.js"
@@ -140,7 +141,7 @@ export class Asset {
inline(): Inline | undefined {
const source = this.source
if (source.type !== "bytes" && source.type !== "base64") return undefined
const base64 = source.type === "base64" ? source.data : (this.#base64 ??= Encoding.encodeBase64(source.data))
const base64 = source.type === "base64" ? source.data : (this.#base64 ??= Base64.encode(source.data))
const mime = this.mediaType.toLowerCase()
return { mime, base64, dataUrl: `data:${mime};base64,${base64}` }
}
@@ -155,7 +156,7 @@ export class Asset {
return Effect.fail(invalid(`Cannot materialize provider ref ${source.provider}:${source.id}`))
const decoded =
source.type === "base64"
? Effect.fromResult(Encoding.decodeBase64(source.data)).pipe(
? Effect.fromResult(Base64.decode(source.data)).pipe(
Effect.mapError((cause) => invalid(`Media asset contains invalid base64 data`, cause)),
)
: download(source, this.headers)
@@ -168,7 +169,7 @@ export class Asset {
const source = this.source
if (source.type === "base64") return Effect.succeed(source.data)
if (this.#base64 !== undefined) return Effect.succeed(this.#base64)
return this.bytes().pipe(Effect.map((data) => (this.#base64 = Encoding.encodeBase64(data))))
return this.bytes().pipe(Effect.map((data) => (this.#base64 = Base64.encode(data))))
})
}
@@ -183,7 +184,7 @@ export class Asset {
toJSON() {
const source = this.source
return {
source: source.type === "bytes" ? { ...source, data: Encoding.encodeBase64(source.data) } : source,
source: source.type === "bytes" ? { ...source, data: Base64.encode(source.data) } : source,
info: this.info,
providerMetadata: this.providerMetadata,
}
@@ -6,7 +6,7 @@ import { Auth } from "../route/auth.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { Protocol } from "../route/protocol.js"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { HttpTransport } from "../route/transport/index.js"
import {
AIError,
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../generation.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
@@ -1,4 +1,5 @@
import { Effect, Encoding, Schema } from "effect"
import { Effect, Schema } from "effect"
import { Base64 } from "effect/encoding"
import { Route } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
@@ -610,7 +611,7 @@ interface ParserState {
readonly reasoningRedactedContent: Readonly<Record<number, Uint8Array[]>>
}
const encodeRedactedContent = (chunks: ReadonlyArray<Uint8Array>) => Encoding.encodeBase64(concatBytes(chunks))
const encodeRedactedContent = (chunks: ReadonlyArray<Uint8Array>) => Base64.encode(concatBytes(chunks))
const step = (state: ParserState, event: BedrockEvent) =>
Effect.gen(function* () {
@@ -659,7 +660,7 @@ const step = (state: ParserState, event: BedrockEvent) =>
const events: LLMEvent[] = []
const redactedChunk = yield* (() => {
if (reasoning.redactedContent === undefined) return Effect.succeed(undefined)
return Effect.fromResult(Encoding.decodeBase64(reasoning.redactedContent)).pipe(
return Effect.fromResult(Base64.decode(reasoning.redactedContent)).pipe(
Effect.mapError((cause) =>
ProviderShared.eventError(
ADAPTER,
@@ -1,6 +1,7 @@
import { EventStreamCodec } from "@smithy/eventstream-codec"
import { fromUtf8, toUtf8 } from "@smithy/util-utf8"
import { Effect, Encoding, Stream } from "effect"
import { Effect, Stream } from "effect"
import { Base64 } from "effect/encoding"
import { AIError, AIErrorReason, InvalidProviderOutputError } from "../schema/index.js"
import { Framing } from "../route/framing.js"
import { ProviderShared } from "./shared.js"
@@ -47,7 +48,7 @@ const consumeFrames = (route: string) => (state: FrameBufferState, input: FrameI
route,
classification: "incomplete-stream",
message: `Incomplete Bedrock Converse event-stream frame: ${remaining.length} buffered bytes remain at end of stream`,
body: Encoding.encodeBase64(remaining),
body: Base64.encode(remaining),
}),
})
return [state, []] as const
@@ -68,7 +69,7 @@ const consumeFrames = (route: string) => (state: FrameBufferState, input: FrameI
`Failed to decode Bedrock Converse event-stream frame: ${
error instanceof Error ? error.message : String(error)
}`,
Encoding.encodeBase64(view.subarray(0, totalLength)),
Base64.encode(view.subarray(0, totalLength)),
error,
),
})
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../generation.js"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { Media } from "../media.js"
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
import { mergeJsonRecords, type OpenString } from "../schema/index.js"
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
import { mergeJsonRecords, type OpenString } from "../schema/index.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Duration, Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../generation.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
+3 -2
View File
@@ -1,4 +1,5 @@
import { Effect, Encoding, Schema } from "effect"
import { Effect, Schema } from "effect"
import { Base64 } from "effect/encoding"
import { Protocol } from "../route/protocol.js"
import { HttpTransport } from "../route/transport/index.js"
import { LLMEvent, LLMRequest, Message, ToolResultPart } from "../schema/index.js"
@@ -135,7 +136,7 @@ const HOSTED_TOOLS = {
"Meta returned an image without data",
ProviderShared.encodeJson(raw),
)
const data = yield* Effect.fromResult(Encoding.decodeBase64(item.result)).pipe(
const data = yield* Effect.fromResult(Base64.decode(item.result)).pipe(
Effect.mapError((cause) =>
ProviderShared.eventError(
ADAPTER,
@@ -1,5 +1,5 @@
import { Effect, Schema, Stream } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { Framing } from "../route/framing.js"
import type { HttpContext } from "../schema/index.js"
import {
@@ -1,5 +1,6 @@
import { Effect, Encoding, Schema } from "effect"
import { Headers } from "effect/unstable/http"
import { Effect, Schema } from "effect"
import { Base64 } from "effect/encoding"
import { Headers } from "effect/http"
import { Route } from "../route/client.js"
import { Auth } from "../route/auth.js"
import { Endpoint } from "../route/endpoint.js"
@@ -249,7 +250,7 @@ const checkpointBody = {
const hostedToolResult = Effect.fn("OpenAIResponses.hostedToolResult")(function* (item: ResponsesHostedTools.Item) {
const isError = item.error !== undefined && item.error !== null
if (item.type === "image_generation_call" && item.result) {
yield* Effect.fromResult(Encoding.decodeBase64(item.result)).pipe(
yield* Effect.fromResult(Base64.decode(item.result)).pipe(
Effect.mapError((cause) =>
ProviderShared.eventError(ADAPTER, "OpenAI Responses returned invalid image base64", undefined, cause),
),
@@ -1,5 +1,5 @@
import { Duration, Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../generation.js"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { Media } from "../media.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Duration, Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../generation.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { Tool } from "@opencode/schema/tool"
import { Effect, Option, Schema } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientRequest } from "effect/http"
import { Media } from "../media.js"
import {
InvalidProviderOutputError,
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
@@ -1,6 +1,6 @@
import { AwsV4Signer } from "aws4fetch"
import { Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { Auth, type AuthInput } from "../../route/auth.js"
import { AIError, AuthenticationError } from "../../schema/index.js"
import { ProviderShared } from "../shared.js"
@@ -1,4 +1,5 @@
import { Effect, Encoding, Schema } from "effect"
import { Effect, Schema } from "effect"
import { Base64 } from "effect/encoding"
import type { MediaPart } from "../../schema/index.js"
import { ProviderShared } from "../shared.js"
@@ -78,12 +79,12 @@ function documentName(filename: string | undefined, names: Set<string>) {
const mediaBase64 = Effect.fn("BedrockMedia.mediaBase64")(function* (part: MediaPart) {
const media = yield* ProviderShared.requireInlineMedia("Bedrock Converse", part.media)
const bytes = yield* Effect.fromResult(Encoding.decodeBase64(media.base64)).pipe(
const bytes = yield* Effect.fromResult(Base64.decode(media.base64)).pipe(
Effect.mapError((cause) =>
ProviderShared.invalidRequest("Bedrock Converse media data must be valid base64", cause),
),
)
return Encoding.encodeBase64(bytes)
return Base64.encode(bytes)
})
// Route by MIME. Known image/document formats lower into a typed block; anything
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../../generation.js"
import type { Media } from "../../media.js"
import { MediaProtocol } from "../../route/media-protocol.js"
@@ -1,4 +1,5 @@
import { Effect, Encoding } from "effect"
import { Effect } from "effect"
import { Base64 } from "effect/encoding"
import { Media } from "../../media.js"
import type { MediaProtocol } from "../../route/media-protocol.js"
import { mergeJsonRecords, type AIError, type ProviderID } from "../../schema/index.js"
@@ -10,7 +11,7 @@ export const inlineBytes = (route: string, asset: Media.Asset): Effect.Effect<Ui
if (asset.source.type === "bytes") return Effect.succeed(asset.source.data)
const inline = asset.inline()
if (!inline) return Effect.fail(ProviderShared.inlineRequired(route, asset))
return Effect.fromResult(Encoding.decodeBase64(inline.base64)).pipe(
return Effect.fromResult(Base64.decode(inline.base64)).pipe(
Effect.mapError((cause) => ProviderShared.invalidRequest(`${route} media contains invalid base64 data`, cause)),
)
}
@@ -52,7 +53,7 @@ export const decodedAsset = (
mediaType: string | undefined,
options?: Media.AssetOptions,
) =>
Effect.fromResult(Encoding.decodeBase64(data)).pipe(
Effect.fromResult(Base64.decode(data)).pipe(
Effect.mapError((cause) => invalid(`${label} contains invalid base64 data`, cause)),
Effect.map((bytes) => Media.bytes(bytes, mediaType, options)),
)
@@ -63,6 +63,9 @@ const objectRoot = (schema: JsonSchema): JsonSchema => {
schema.anyOf.some((branch) => isRecord(branch) && branch.type === "object" && Object.keys(branch).length === 1)
)
return { type: "object", ...Object.fromEntries(Object.entries(schema).filter(([key]) => key !== "anyOf")) }
// Effect 4 represents an empty Struct as `not: { type: "null" }`; an object root already excludes null.
if (isRecord(schema.not) && schema.not.type === "null" && Object.keys(schema.not).length === 1)
return { type: "object", ...Object.fromEntries(Object.entries(schema).filter(([key]) => key !== "not")) }
return { type: "object", ...schema }
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import type { Status } from "../generation.js"
import { Media } from "../media.js"
import { MediaProtocol } from "../route/media-protocol.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Duration, Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import type { HttpClientResponse } from "effect/http"
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
@@ -1,5 +1,5 @@
import { Effect, Schema } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientRequest } from "effect/http"
import {
EvaluationAnswer,
EvaluationInput,
+2 -2
View File
@@ -1,5 +1,5 @@
import { Config, Effect, Option, Redacted } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { AuthenticationError, AIError, type HttpOptions } from "../schema/index.js"
export class MissingCredentialError extends Error {
@@ -95,7 +95,7 @@ export const optional = (secret: Secret | undefined, source = "optional value")
export const config = (name: string) =>
credential(
Effect.gen(function* () {
const secret = yield* Config.option(Config.redacted(name))
const secret = yield* Config.option(Config.Redacted(name))
if (Option.isSome(secret) && Redacted.value(secret.value) !== "") return secret.value
return yield* Effect.fail(new MissingCredentialError(name, `${name} is not set`))
}),
+1 -1
View File
@@ -1,5 +1,5 @@
import { Context, type Effect } from "effect"
import type { HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import type { HttpClientRequest, HttpClientResponse } from "effect/http"
import type { AIError } from "../schema/errors.js"
// The service tag lives in its own leaf module so `Media.Asset` (imported by the schema layer) can require the
+1 -1
View File
@@ -6,7 +6,7 @@ import {
HttpClientError,
HttpClientRequest,
HttpClientResponse,
} from "effect/unstable/http"
} from "effect/http"
import { HttpContext, HttpRateLimitDetails, AIError, TransportError } from "../schema/index.js"
import { classifyProviderFailure, providerErrorMessage } from "../provider-error.js"
import { Service, type HttpMiddleware, type Interface } from "./executor-service.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, Stream } from "effect"
import { makeParser, type Event } from "effect/unstable/encoding/Sse"
import { makeParser, type Event } from "effect/encoding/Sse"
import { AIError, InvalidProviderOutputError } from "../schema/index.js"
/**
+1 -1
View File
@@ -1,5 +1,5 @@
import { Clock, Duration, Effect, Schema, type Stream } from "effect"
import { HttpClientResponse } from "effect/unstable/http"
import { HttpClientResponse } from "effect/http"
import type { Snapshot, Status } from "../generation.js"
import { Media } from "../media.js"
import type { AuthInput } from "./auth.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Duration, Effect, Schedule, Schema, Stream } from "effect"
import { Headers, HttpClientRequest, type HttpClientResponse } from "effect/unstable/http"
import { Headers, HttpClientRequest, type HttpClientResponse } from "effect/http"
import { Auth, type AuthInput } from "./auth.js"
import { Endpoint } from "./endpoint.js"
import { RequestExecutorService, type Interface } from "./executor-service.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientRequest } from "effect/http"
import { Auth } from "../auth.js"
import { render as renderEndpoint } from "../endpoint.js"
import { Framing } from "../framing.js"
@@ -1,5 +1,5 @@
import type { Effect, Scope, Stream } from "effect"
import type { Headers } from "effect/unstable/http"
import type { Headers } from "effect/http"
import type { AIError, HttpContext } from "../../schema/index.js"
export interface WebSocketChannelExecutor {
+2 -2
View File
@@ -1,6 +1,6 @@
import { Cause, Effect, Queue, Stream } from "effect"
import { Headers } from "effect/unstable/http"
import { Socket } from "effect/unstable/socket"
import { Headers } from "effect/http"
import { Socket } from "effect/socket"
import {
AIError,
AIErrorReason,
+2 -1
View File
@@ -1,4 +1,5 @@
import { Schema } from "effect"
import { extendSchema } from "@opencode/schema/schema"
import { LLM } from "@opencode/schema/llm"
import { ContentBlockID, ToolCallID } from "./ids.js"
import {
@@ -339,7 +340,7 @@ const toolCallID = (value: ToolCallID | string) => ToolCallID.make(value)
* Lets consumers write `events.filter(LLMEvent.is.toolCall)` instead of
* `events.filter(LLMEvent.guards["tool-call"])`.
*/
export const LLMEvent = Object.assign(llmEventTagged, {
export const LLMEvent = extendSchema(llmEventTagged, {
compaction: CompactionPart.make,
stepStart: StepStart.make,
textStart: (input: WithID<TextStart, ContentBlockID>) => TextStart.make({ ...input, id: contentBlockID(input.id) }),
+9 -8
View File
@@ -1,4 +1,5 @@
import { Schema } from "effect"
import { extendSchema } from "@opencode/schema/schema"
import { Tool } from "@opencode/schema/tool"
import {
CacheHint,
@@ -28,7 +29,7 @@ export type SystemPart = Schema.Schema.Type<typeof systemPartSchema>
const makeSystemPart = (text: string): SystemPart => ({ type: "text", text })
export const SystemPart = Object.assign(systemPartSchema, {
export const SystemPart = extendSchema(systemPartSchema, {
make: makeSystemPart,
content: (input?: string | SystemPart | ReadonlyArray<SystemPart>) => {
if (input === undefined) return []
@@ -76,7 +77,7 @@ const toolResultValueSchema = Schema.Union([
export type ToolResultValue = Schema.Schema.Type<typeof toolResultValueSchema>
const isToolResultValue = Schema.is(toolResultValueSchema)
export const ToolResultValue = Object.assign(toolResultValueSchema, {
export const ToolResultValue = extendSchema(toolResultValueSchema, {
is: isToolResultValue,
make: (value: unknown, type: ToolResultValue["type"] = "json"): ToolResultValue => {
if (isToolResultValue(value)) return value
@@ -90,7 +91,7 @@ export interface ToolOutput {
readonly content: ReadonlyArray<Tool.Content>
}
export const ToolOutput = Object.assign(
export const ToolOutput = extendSchema(
Schema.Struct({
structured: Schema.Unknown,
content: Schema.Array(Tool.Content),
@@ -127,7 +128,7 @@ const toolResultText = (value: unknown) => {
}
}
export const ToolCallPart = Object.assign(
export const ToolCallPart = extendSchema(
Schema.Struct({
type: Schema.Literal("tool-call"),
id: Schema.String,
@@ -145,7 +146,7 @@ export const ToolCallPart = Object.assign(
)
export type ToolCallPart = Schema.Schema.Type<typeof ToolCallPart>
export const ToolResultPart = Object.assign(
export const ToolResultPart = extendSchema(
Schema.Struct({
type: Schema.Literal("tool-result"),
id: Schema.String,
@@ -209,7 +210,7 @@ const compactionPartSchema = Schema.Struct({
)
.annotate({ identifier: "LLM.Content.Compaction" })
export type CompactionPart = typeof compactionPartSchema.Type
export const CompactionPart = Object.assign(compactionPartSchema, {
export const CompactionPart = extendSchema(compactionPartSchema, {
make: (input: Omit<CompactionPart, "type" | "encrypted" | "text"> & CompactionContent): CompactionPart =>
Schema.decodeUnknownSync(compactionPartSchema)({ type: "compaction", ...input }),
})
@@ -326,7 +327,7 @@ export type ToolNamespaceEntryInput = ToolNamespaceInput & { readonly type: "nam
export const ToolNamespace: Schema.Codec<ToolNamespace> & {
readonly make: (input: ToolNamespace | ToolNamespaceInput) => ToolNamespace
} = Object.assign(
} = extendSchema(
Schema.Struct({
type: Schema.Literal("namespace"),
name: Schema.String,
@@ -346,7 +347,7 @@ export type ToolEntry = ToolDefinition | ToolNamespace
export type ToolEntryInput = ToolDefinition.Input | ToolNamespaceEntryInput
export const ToolEntry: Schema.Codec<ToolEntry> & {
readonly make: (input: ToolEntryInput) => ToolEntry
} = Object.assign(
} = extendSchema(
Schema.Union([ToolDefinition, ToolNamespace]).pipe(
Schema.toTaggedUnion("type"),
Schema.annotate({ identifier: "LLM.ToolEntry" }),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Effect, Schema, Stream } from "effect"
import { extendSchema } from "@opencode/schema/schema"
import { ProgressEvent, QueuedEvent } from "./generation.js"
import { Media } from "./media.js"
import { MediaModel, composeRoute, tryRequest } from "./media-model.js"
@@ -141,7 +142,7 @@ const speechEventTagged = Schema.Union([
SpeechTimestampsEvent,
SpeechFinishEvent,
]).pipe(Schema.toTaggedUnion("type"))
export const SpeechEvent = Object.assign(speechEventTagged, {
export const SpeechEvent = extendSchema(speechEventTagged, {
is: {
generationQueued: speechEventTagged.guards["generation-queued"],
generationProgress: speechEventTagged.guards["generation-progress"],
+2 -1
View File
@@ -231,7 +231,8 @@ export const toDefinitions = (tools: Tools): ReadonlyArray<ToolDefinitionClass>
)
const toJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
const document = Schema.toJsonSchemaDocument(schema)
// Keep provider-facing tool schemas closed; Effect 4's default now emits additionalProperties: true.
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
if (Object.keys(document.definitions).length === 0) return document.schema
return { ...document.schema, $defs: document.definitions }
}
+2 -1
View File
@@ -1,4 +1,5 @@
import { Effect, Schema, Stream } from "effect"
import { extendSchema } from "@opencode/schema/schema"
import { Generation, ProgressEvent, QueuedEvent, type AwaitOptions } from "./generation.js"
import { Media } from "./media.js"
import { MediaModel, composeRoute, tryRequest } from "./media-model.js"
@@ -159,7 +160,7 @@ const transcriptionEventTagged = Schema.Union([
TranscriptionSegmentEvent,
TranscriptionFinishEvent,
]).pipe(Schema.toTaggedUnion("type"))
export const TranscriptionEvent = Object.assign(transcriptionEventTagged, {
export const TranscriptionEvent = extendSchema(transcriptionEventTagged, {
is: {
generationQueued: transcriptionEventTagged.guards["generation-queued"],
generationProgress: transcriptionEventTagged.guards["generation-progress"],
+2 -1
View File
@@ -1,4 +1,5 @@
import { Effect, Schema, Stream } from "effect"
import { extendSchema } from "@opencode/schema/schema"
import { Generation, ProgressEvent, QueuedEvent, type AwaitOptions } from "./generation.js"
import { Media } from "./media.js"
import { MediaModel, composeRoute, tryRequest } from "./media-model.js"
@@ -136,7 +137,7 @@ export const VideoFinishEvent = Schema.Struct({
const videoEventTagged = Schema.Union([QueuedEvent, ProgressEvent, VideoOutputEvent, VideoFinishEvent]).pipe(
Schema.toTaggedUnion("type"),
)
export const VideoEvent = Object.assign(videoEventTagged, {
export const VideoEvent = extendSchema(videoEventTagged, {
is: {
generationQueued: videoEventTagged.guards["generation-queued"],
generationProgress: videoEventTagged.guards["generation-progress"],
+1 -1
View File
@@ -30,7 +30,7 @@ type LanguageModel = {
declare const auth: Auth.Definition
declare const optionalAuthModel: LanguageModelFactory<BaseOptions, "optional", LanguageModel>
declare const requiredAuthModel: LanguageModelFactory<BaseOptions, "required", LanguageModel>
const configApiKey = Config.redacted("OPENAI_API_KEY")
const configApiKey = Config.Redacted("OPENAI_API_KEY")
OpenAIChat.route.model({ id: "gpt-4.1-mini" })
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { LLM } from "../src/index.js"
import { Auth } from "../src/route/auth.js"
import * as OpenAIChat from "../src/protocols/openai-chat.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { expect } from "bun:test"
import { Effect } from "effect"
import { FetchHttpClient } from "effect/unstable/http"
import { FetchHttpClient } from "effect/http"
import { LLM, LLMRequest, Message } from "../src/index.js"
import { LLMClient } from "../src/route/client.js"
import { OpenAI } from "../src/providers.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { Effect, Ref, Schema } from "effect"
import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import { HttpClientRequest, HttpClientResponse } from "effect/http"
import {
LLM,
LLMRequest,
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { Evaluation, EvaluationClient } from "../src/experimental.js"
import { OpenCodeZen, OpenRouter, TypeSafeAI, VercelAIGateway } from "../src/providers.js"
import { it } from "./lib/effect.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Deferred, Effect, Fiber, Layer, Ref, Stream } from "effect"
import { Headers, HttpClientError, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientError, HttpClientRequest } from "effect/http"
import { LLM, AIError, HttpContext, InvalidProviderOutputError, TransportError } from "../src/index.js"
import { LLMClient, RequestExecutor, WebSocketTransport, type WebSocketChannelExecutor } from "../src/route.js"
import { route } from "../src/protocols/openai-chat.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Layer, Stream } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { Image, ImageClient, Media } from "../src/index.js"
import { BlackForestLabs, Fal, Google, OpenAI, Replicate, Stability, XAI, ZAI } from "../src/providers.js"
import { it } from "./lib/effect.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { Effect, Fiber, Layer, Ref } from "effect"
import * as TestClock from "effect/testing/TestClock"
import { HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import { HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/http"
import { LLMClient, RequestExecutor } from "../../src/route.js"
import type { Service as LLMClientService } from "../../src/route/client.js"
import type { Service as RequestExecutorService } from "../../src/route/executor.js"
+1 -1
View File
@@ -2,7 +2,7 @@ import { describe, expect } from "bun:test"
import { NodeFileSystem } from "@effect/platform-node"
import { Effect, Ref, Schema } from "effect"
import { FileSystem } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { AIError, Media, Message } from "../src/index.js"
import { it } from "./lib/effect.js"
import { dynamicResponse, scriptedResponses } from "./lib/http.js"
+1 -1
View File
@@ -3,7 +3,7 @@ import { mkdtemp, rm } from "node:fs/promises"
import { tmpdir } from "node:os"
import { join } from "node:path"
import { Effect, Layer } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { AIError, LLMEvent, Media, SpeechEvent, TranscriptionEvent } from "../src/index.js"
import { RequestExecutor } from "../src/route.js"
import { AI } from "../src/promise.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { expect, test } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { Auth, LLM, LLMClient, LLMRequest, Message, ReasoningPart, ToolDefinition } from "../../src/index.js"
import { Alibaba } from "../../src/providers.js"
import { compileRequest } from "../../src/route/client.js"
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import {
CacheHint,
LLM,
@@ -1,8 +1,9 @@
import { EventStreamCodec } from "@smithy/eventstream-codec"
import { fromUtf8, toUtf8 } from "@smithy/util-utf8"
import { describe, expect } from "bun:test"
import { Effect, Encoding, Ref, Schema, Stream } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { Effect, Ref, Schema, Stream } from "effect"
import { Base64 } from "effect/encoding"
import { HttpClientRequest } from "effect/http"
import {
Media,
CacheHint,
@@ -866,7 +867,7 @@ describe("Bedrock Converse route", () => {
reason: { _tag: "InvalidProviderOutput", classification: "incomplete-stream" },
message: `Incomplete Bedrock Converse event-stream frame: ${partial.length} buffered bytes remain at end of stream`,
})
expect(error.reason.body).toBe(Encoding.encodeBase64(partial))
expect(error.reason.body).toBe(Base64.encode(partial))
}
}),
)
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { LLM, Message } from "../../src/index.js"
import { AmazonBedrockMantle } from "../../src/providers.js"
import { model } from "../../src/providers/amazon-bedrock/mantle.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { ConfigProvider, Effect, Schema } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { LLM, LLMEvent } from "../../src/index.js"
import { CloudflareAIGateway } from "../../src/providers/cloudflare-ai-gateway.js"
import { CloudflareWorkersAI } from "../../src/providers/cloudflare-workers-ai.js"
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { Effect } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { LanguageModel, LLM, Message, ToolCallPart } from "../../src/index.js"
import { GoogleVertex, GoogleVertexChat, GoogleVertexMessages, GoogleVertexResponses } from "../../src/providers.js"
import { LLMClient } from "../../src/route.js"
@@ -1,6 +1,6 @@
import { expect } from "bun:test"
import { Effect, Layer } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { Image, ImageClient, LLM, LLMEvent, LLMRequest, Media, Message, ToolDefinition } from "../../src/index.js"
import { Meta } from "../../src/providers/meta.js"
import { MetaMessages } from "../../src/protocols/meta-messages.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { expect } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { Auth, LLM, LLMClient } from "../../src/index.js"
import { Meta } from "../../src/providers/index.js"
import { OpenAIChat } from "../../src/protocols/openai-chat.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { LLM } from "../../src/index.js"
import { MiniMax } from "../../src/providers.js"
import { AnthropicMessages } from "../../src/protocols/anthropic-messages.js"
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { LLM, LLMEvent, Message, ToolDefinition, Media } from "../../src/index.js"
import { Mistral } from "../../src/providers/index.js"
import { MistralChat } from "../../src/protocols/index.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { expect } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { Auth, LLM, LLMClient, Message, ReasoningPart, ToolDefinition } from "../../src/index.js"
import { Moonshot } from "../../src/providers.js"
import { AnthropicMessages } from "../../src/protocols/anthropic-messages.js"
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { LLM, Message, ToolDefinition } from "../../src/index.js"
import {
AmazonBedrock,
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Ref, Schema, Stream } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import {
Media,
HttpOptions,
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import { Effect, Schema } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { LLM, LLMRequest, Message, ToolCallPart, ToolChoice, ToolDefinition } from "../../src/index.js"
import { Auth, LLMClient } from "../../src/route.js"
import { compileRequest } from "../../src/route/client.js"
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Stream } from "effect"
import { Socket } from "effect/unstable/socket"
import { Socket } from "effect/socket"
import { LLM, LLMRequest, Message, ToolRuntime } from "../../src/index.js"
import {
LLMClient,
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { ConfigProvider, Effect, Layer, Logger, Ref, Schema, Stream } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientRequest } from "effect/http"
import {
Media,
LLM,
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Headers, HttpClientRequest } from "effect/http"
import { Image, ImageClient } from "../../src/index.js"
import { XAI } from "../../src/providers.js"
import { Auth } from "../../src/route.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { Image, ImageClient } from "../../src/index.js"
import { ZAI } from "../../src/providers.js"
import { it } from "../lib/effect.js"
+1 -1
View File
@@ -1,6 +1,6 @@
import { expect } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Headers } from "effect/http"
import { Auth, LLM, LLMClient, Message, ReasoningPart, ToolDefinition } from "../../src/index.js"
import { ZAI, ZAICodingPlan } from "../../src/providers.js"
import { compileRequest } from "../../src/route/client.js"
+1 -1
View File
@@ -1,7 +1,7 @@
import { HttpRecorder } from "@opencode/http-recorder"
import { NodeSocket } from "@effect/platform-node"
import { Layer } from "effect"
import { Socket } from "effect/unstable/socket"
import { Socket } from "effect/socket"
import * as path from "node:path"
import { fileURLToPath } from "node:url"
import { LLMClient, RequestExecutor } from "../src/route.js"
+4 -3
View File
@@ -1,5 +1,6 @@
import { describe, expect } from "bun:test"
import { Effect, Encoding, Layer, Stream } from "effect"
import { Effect, Layer, Stream } from "effect"
import { Base64 } from "effect/encoding"
import { Speech, SpeechClient, SpeechEvent } from "../src/index.js"
import { Cartesia, Deepgram, ElevenLabs, Google, OpenAI } from "../src/providers.js"
import { it } from "./lib/effect.js"
@@ -47,7 +48,7 @@ describe("Speech", () => {
JSON.stringify({
candidates: [
{
content: { parts: [{ inlineData: { mimeType: "audio/wav", data: Encoding.encodeBase64(bytes) } }] },
content: { parts: [{ inlineData: { mimeType: "audio/wav", data: Base64.encode(bytes) } }] },
finishReason: "STOP",
},
],
@@ -244,7 +245,7 @@ describe("Speech", () => {
Effect.gen(function* () {
const record = (bytes: ReadonlyArray<number>, character: string, start: number) =>
JSON.stringify({
audio_base64: Encoding.encodeBase64(Uint8Array.from(bytes)),
audio_base64: Base64.encode(Uint8Array.from(bytes)),
alignment: {
characters: [character],
character_start_times_seconds: [start],
+1 -1
View File
@@ -1,7 +1,7 @@
import { describe, expect } from "bun:test"
import { Effect, Fiber, Layer, Stream } from "effect"
import * as TestClock from "effect/testing/TestClock"
import { HttpClientRequest } from "effect/unstable/http"
import { HttpClientRequest } from "effect/http"
import { Media, Transcription, TranscriptionClient, type TranscriptionEvent } from "../src/index.js"
import { AssemblyAI, Deepgram, ElevenLabs, Google, OpenAI } from "../src/providers.js"
import { it } from "./lib/effect.js"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Schema, SchemaGetter } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api"
import { Pty } from "@opencode/schema/pty"
import { Worktree } from "@opencode/schema/worktree"
+2 -2
View File
@@ -1,8 +1,8 @@
import type { Page } from "@playwright/test"
import type { JsonValue, OpenCodeEvent, SessionMessageInfo } from "@opencode/client/promise"
import { Duration, Effect, Layer } from "effect"
import { HttpRouter, HttpServer, HttpServerResponse } from "effect/unstable/http"
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi"
import { HttpRouter, HttpServer, HttpServerResponse } from "effect/http"
import { HttpApiBuilder, HttpApiSchema } from "effect/http-api"
import { SERVER } from "./app"
import { MockApi, MockBadRequest, MockInternal, MockNotFound, MockShellNotFound, MockUnsupported } from "./mock-api"
import { installSseTransport } from "./sse-transport"
+14 -5
View File
@@ -23,14 +23,23 @@ export function withInitial<S extends Schema.ConstraintCodec<object, unknown>>(
initial: NoInfer<S["Type"]>,
) {
const schema = isMigrated(definition) ? definition.current : definition
const read = isMigrated(definition)
? SchemaParser.decodeUnknownResult(definition.read, { onExcessProperty: "preserve" })
: Result.succeed<unknown>
const read = isMigrated(definition) ? SchemaParser.decodeUnknownResult(definition.read) : Result.succeed<unknown>
const encode = Schema.encodeUnknownSync(schema)
return Schema.Unknown.pipe(
Schema.decode<Schema.Unknown>({
decode: SchemaGetter.transformOrFail((value) =>
Effect.fromResult(Result.map(read(value), (stored) => merge(initial, recover(schema.ast, stored, initial)))),
decode: SchemaGetter.transformEffect((value) =>
Effect.fromResult(
Result.map(read(value), (stored) =>
merge(
initial,
recover(
schema.ast,
Predicate.isObject(value) && Predicate.isObject(stored) ? { ...value, ...stored } : stored,
initial,
),
),
),
),
),
encode: SchemaGetter.transform((value) => encode(value)),
}),
+95 -95
View File
@@ -1,10 +1,10 @@
import { Argument, Flag, GlobalFlag } from "effect/unstable/cli"
import { Argument, Flag, GlobalFlag } from "effect/cli"
import { Schema } from "effect"
import { Spec } from "../framework/spec"
import { Updater } from "../services/updater"
export const PrintLogs = GlobalFlag.setting("print-logs")({
flag: Flag.boolean("print-logs").pipe(
export const PrintLogs = GlobalFlag.Setting("print-logs")({
flag: Flag.Boolean("print-logs").pipe(
Flag.withDescription("Print logs to stderr (server logs require --standalone)"),
Flag.withDefault(false),
),
@@ -13,23 +13,23 @@ export const PrintLogs = GlobalFlag.setting("print-logs")({
declare const OPENCODE_CLI_NAME: string | undefined
const ServerParams = {
standalone: Flag.boolean("standalone").pipe(
standalone: Flag.Boolean("standalone").pipe(
Flag.withDescription("Run with a private server instead of the background service"),
Flag.withDefault(false),
),
server: Flag.string("server").pipe(
server: Flag.String("server").pipe(
Flag.withDescription("Connect to a server URL instead of the background service"),
Flag.optional,
),
}
const PermissionParams = {
auto: Flag.boolean("auto").pipe(
auto: Flag.Boolean("auto").pipe(
Flag.withDescription("Auto-approve permissions that are not explicitly denied"),
Flag.withDefault(false),
),
yolo: Flag.boolean("yolo").pipe(Flag.withDefault(false), Flag.withHidden),
dangerouslySkipPermissions: Flag.boolean("dangerously-skip-permissions").pipe(
yolo: Flag.Boolean("yolo").pipe(Flag.withDefault(false), Flag.withHidden),
dangerouslySkipPermissions: Flag.Boolean("dangerously-skip-permissions").pipe(
Flag.withDefault(false),
Flag.withHidden,
),
@@ -40,32 +40,32 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
params: {
...ServerParams,
...PermissionParams,
directory: Argument.string("directory").pipe(
directory: Argument.String("directory").pipe(
Argument.withDescription("Directory to start OpenCode in"),
Argument.optional,
),
continue: Flag.boolean("continue").pipe(
continue: Flag.Boolean("continue").pipe(
Flag.withAlias("c"),
Flag.withDescription("Continue the last session"),
Flag.withDefault(false),
),
session: Flag.string("session").pipe(
session: Flag.String("session").pipe(
Flag.withAlias("s"),
Flag.withDescription("Session ID to continue, or to create if it does not exist"),
Flag.optional,
),
prompt: Flag.string("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
prompt: Flag.String("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
},
commands: [
Spec.make("upgrade", {
description: "Upgrade OpenCode to the latest or a specific version",
aliases: ["update"],
params: {
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Version to upgrade to (with or without a leading v)"),
Argument.optional,
),
method: Flag.choice("method", Updater.methods).pipe(
method: Flag.Literals("method", Updater.methods).pipe(
Flag.withAlias("m"),
Flag.withDescription("Installation method to use"),
Flag.optional,
@@ -75,21 +75,21 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("uninstall", {
description: "Uninstall OpenCode and remove all related files",
params: {
keepConfig: Flag.boolean("keep-config").pipe(
keepConfig: Flag.Boolean("keep-config").pipe(
Flag.withAlias("c"),
Flag.withDescription("Keep configuration files"),
Flag.withDefault(false),
),
keepData: Flag.boolean("keep-data").pipe(
keepData: Flag.Boolean("keep-data").pipe(
Flag.withAlias("d"),
Flag.withDescription("Keep session data and snapshots"),
Flag.withDefault(false),
),
dryRun: Flag.boolean("dry-run").pipe(
dryRun: Flag.Boolean("dry-run").pipe(
Flag.withDescription("Show what would be removed without removing"),
Flag.withDefault(false),
),
force: Flag.boolean("force").pipe(
force: Flag.Boolean("force").pipe(
Flag.withAlias("f"),
Flag.withDescription("Skip confirmation prompts"),
Flag.withDefault(false),
@@ -101,17 +101,17 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "Make a request to the running server",
params: {
...ServerParams,
request: Argument.string("operation | method path").pipe(
request: Argument.String("operation | method path").pipe(
Argument.withDescription("OpenAPI operation ID, or an HTTP method followed by a path"),
Argument.variadic({ min: 1, max: 2 }),
),
data: Flag.string("data").pipe(Flag.withAlias("d"), Flag.withDescription("Request body"), Flag.optional),
header: Flag.string("header").pipe(
data: Flag.String("data").pipe(Flag.withAlias("d"), Flag.withDescription("Request body"), Flag.optional),
header: Flag.String("header").pipe(
Flag.withAlias("H"),
Flag.withDescription("Request header in name:value form"),
Flag.atMost(100),
),
param: Flag.keyValuePair("param").pipe(Flag.withDescription("OpenAPI path or query parameter"), Flag.optional),
param: Flag.KeyValuePair("param").pipe(Flag.withDescription("OpenAPI path or query parameter"), Flag.optional),
},
}),
Spec.make("debug", {
@@ -122,7 +122,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("paths", {
description: "Show global paths (data, config, cache, state)",
params: {
name: Argument.choice("name", [
name: Argument.Literals("name", [
"db",
"home",
"data",
@@ -148,7 +148,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "list integrations and credentials",
params: {
...ServerParams,
format: Flag.choice("format", ["default", "json"]).pipe(
format: Flag.Literals("format", ["default", "json"]).pipe(
Flag.withDescription("Output format"),
Flag.withDefault("default"),
),
@@ -158,12 +158,12 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "connect an integration",
params: {
...ServerParams,
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Integration ID, name, or well-known provider URL"),
Argument.optional,
),
method: Flag.string("method").pipe(Flag.withDescription("Authentication method ID"), Flag.optional),
answer: Flag.string("answer").pipe(
method: Flag.String("method").pipe(Flag.withDescription("Authentication method ID"), Flag.optional),
answer: Flag.String("answer").pipe(
Flag.withDescription("Provider form answer (key=value; repeat for multiple fields)"),
Flag.atMost(100),
),
@@ -173,11 +173,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "log out of a saved account",
params: {
...ServerParams,
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Integration ID or name"),
Argument.optional,
),
credential: Argument.string("credential").pipe(
credential: Argument.String("credential").pipe(
Argument.withDescription("Credential ID or label (opens an account picker when omitted)"),
Argument.optional,
),
@@ -187,7 +187,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "print stored credentials, including secrets, as JSON",
params: {
...ServerParams,
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Integration ID or name (exports every integration when omitted)"),
Argument.optional,
),
@@ -197,7 +197,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "import credentials exported by auth export",
params: {
...ServerParams,
file: Argument.string("file").pipe(
file: Argument.String("file").pipe(
Argument.withDescription("JSON file to import (reads stdin when omitted)"),
Argument.optional,
),
@@ -207,11 +207,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "switch the active account for an integration",
params: {
...ServerParams,
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Integration ID or name"),
Argument.optional,
),
credential: Argument.string("credential").pipe(
credential: Argument.String("credential").pipe(
Argument.withDescription("Credential ID or label (opens an account picker when omitted)"),
Argument.optional,
),
@@ -226,21 +226,21 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("add", {
description: "Add an MCP server to your configuration",
params: {
name: Argument.string("name").pipe(Argument.withDescription("Name of the MCP server")),
command: Argument.string("command").pipe(
name: Argument.String("name").pipe(Argument.withDescription("Name of the MCP server")),
command: Argument.String("command").pipe(
Argument.withDescription("Command and arguments for a local server, passed after --"),
Argument.variadic({ min: 0 }),
),
url: Flag.string("url").pipe(Flag.withDescription("URL for a remote MCP server"), Flag.optional),
header: Flag.keyValuePair("header").pipe(
url: Flag.String("url").pipe(Flag.withDescription("URL for a remote MCP server"), Flag.optional),
header: Flag.KeyValuePair("header").pipe(
Flag.withDescription("HTTP header for a remote server, as name=value"),
Flag.optional,
),
env: Flag.keyValuePair("env").pipe(
env: Flag.KeyValuePair("env").pipe(
Flag.withDescription("Environment variable for a local server, as name=value"),
Flag.optional,
),
global: Flag.boolean("global").pipe(
global: Flag.Boolean("global").pipe(
Flag.withDescription("Write to the global config instead of the project config"),
Flag.withDefault(false),
),
@@ -249,12 +249,12 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("auth", {
description: "Authenticate with an OAuth-capable remote MCP server",
params: {
name: Argument.string("name").pipe(Argument.withDescription("Name of the MCP server"), Argument.optional),
name: Argument.String("name").pipe(Argument.withDescription("Name of the MCP server"), Argument.optional),
},
}),
Spec.make("logout", {
description: "Remove stored OAuth credentials for an MCP server",
params: { name: Argument.string("name").pipe(Argument.withDescription("Name of the MCP server")) },
params: { name: Argument.String("name").pipe(Argument.withDescription("Name of the MCP server")) },
}),
],
}),
@@ -264,7 +264,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("list", {
description: "List plugins",
params: {
builtin: Flag.boolean("builtin").pipe(
builtin: Flag.Boolean("builtin").pipe(
Flag.withDescription("Include built-in server plugins"),
Flag.withDefault(false),
),
@@ -273,13 +273,13 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("add", {
description: "Install a plugin and add it to the global configuration",
params: {
package: Argument.string("package").pipe(Argument.withDescription("npm registry or Git package specifier")),
package: Argument.String("package").pipe(Argument.withDescription("npm registry or Git package specifier")),
},
}),
Spec.make("check", {
description: "Check package plugins for updates",
params: {
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Configured package target"),
Argument.optional,
),
@@ -288,7 +288,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("update", {
description: "Update package plugins",
params: {
target: Argument.string("target").pipe(
target: Argument.String("target").pipe(
Argument.withDescription("Configured package target; omit to update all outdated plugins"),
Argument.optional,
),
@@ -297,7 +297,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("remove", {
description: "Remove a plugin from global configuration",
params: {
package: Argument.string("package").pipe(Argument.withDescription("configured package specifier")),
package: Argument.String("package").pipe(Argument.withDescription("configured package specifier")),
},
}),
],
@@ -310,108 +310,108 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "Show shareable usage statistics",
params: {
...ServerParams,
days: Flag.integer("days").pipe(
days: Flag.Int("days").pipe(
Flag.withSchema(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),
Flag.withDescription("Show the last N days; 0 means today"),
Flag.optional,
),
year: Flag.integer("year").pipe(
year: Flag.Int("year").pipe(
Flag.withSchema(Schema.Int.check(Schema.isBetween({ minimum: 1970, maximum: 9_999 }))),
Flag.withDescription("Show a calendar year"),
Flag.optional,
),
all: Flag.boolean("all").pipe(Flag.withDescription("Show lifetime statistics"), Flag.withDefault(false)),
project: Flag.string("project").pipe(
all: Flag.Boolean("all").pipe(Flag.withDescription("Show lifetime statistics"), Flag.withDefault(false)),
project: Flag.String("project").pipe(
Flag.withDescription('Filter by project ID, or use "." for the current project'),
Flag.optional,
),
models: Flag.boolean("models").pipe(Flag.withDescription("Show model usage"), Flag.withDefault(false)),
tools: Flag.boolean("tools").pipe(Flag.withDescription("Show tool reliability"), Flag.withDefault(false)),
cost: Flag.boolean("cost").pipe(Flag.withDescription("Show cost and token details"), Flag.withDefault(false)),
full: Flag.boolean("full").pipe(Flag.withDescription("Show every detailed section"), Flag.withDefault(false)),
limit: Flag.integer("limit").pipe(
models: Flag.Boolean("models").pipe(Flag.withDescription("Show model usage"), Flag.withDefault(false)),
tools: Flag.Boolean("tools").pipe(Flag.withDescription("Show tool reliability"), Flag.withDefault(false)),
cost: Flag.Boolean("cost").pipe(Flag.withDescription("Show cost and token details"), Flag.withDefault(false)),
full: Flag.Boolean("full").pipe(Flag.withDescription("Show every detailed section"), Flag.withDefault(false)),
limit: Flag.Int("limit").pipe(
Flag.withSchema(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))),
Flag.withDescription("Number of rows in detailed sections"),
Flag.withDefault(5),
),
json: Flag.boolean("json").pipe(Flag.withDescription("Output statistics as JSON"), Flag.withDefault(false)),
json: Flag.Boolean("json").pipe(Flag.withDescription("Output statistics as JSON"), Flag.withDefault(false)),
},
}),
Spec.make("mini", {
description: "Start the minimal interactive interface",
params: {
...ServerParams,
continue: Flag.boolean("continue").pipe(
continue: Flag.Boolean("continue").pipe(
Flag.withAlias("c"),
Flag.withDescription("Continue the last session"),
Flag.withDefault(false),
),
session: Flag.string("session").pipe(
session: Flag.String("session").pipe(
Flag.withAlias("s"),
Flag.withDescription("Session ID to continue, or to create if it does not exist"),
Flag.optional,
),
fork: Flag.boolean("fork").pipe(
fork: Flag.Boolean("fork").pipe(
Flag.withDescription("Fork the session when continuing"),
Flag.withDefault(false),
),
replay: Flag.boolean("replay").pipe(
replay: Flag.Boolean("replay").pipe(
Flag.withDescription("Restore session history on resume and resize (disable with --no-replay)"),
Flag.optional,
),
replayLimit: Flag.integer("replay-limit").pipe(
replayLimit: Flag.Int("replay-limit").pipe(
Flag.withDescription("Limit replay to the newest N messages (default: 200)"),
Flag.optional,
),
model: Flag.string("model").pipe(
model: Flag.String("model").pipe(
Flag.withAlias("m"),
Flag.withDescription("Model to use in the format provider/model"),
Flag.optional,
),
agent: Flag.string("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
prompt: Flag.string("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
demo: Flag.boolean("demo").pipe(Flag.withDefault(false), Flag.withHidden),
agent: Flag.String("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
prompt: Flag.String("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
demo: Flag.Boolean("demo").pipe(Flag.withDefault(false), Flag.withHidden),
},
}),
Spec.make("run", {
description: "Run OpenCode with a message",
params: {
...ServerParams,
message: Argument.string("message").pipe(
message: Argument.String("message").pipe(
Argument.withDescription("Message to send"),
Argument.variadic({ min: 0 }),
),
continue: Flag.boolean("continue").pipe(
continue: Flag.Boolean("continue").pipe(
Flag.withAlias("c"),
Flag.withDescription("Continue the last session"),
Flag.withDefault(false),
),
session: Flag.string("session").pipe(
session: Flag.String("session").pipe(
Flag.withAlias("s"),
Flag.withDescription("Session ID to continue, or to create if it does not exist"),
Flag.optional,
),
fork: Flag.boolean("fork").pipe(
fork: Flag.Boolean("fork").pipe(
Flag.withDescription("Fork the session before continuing"),
Flag.withDefault(false),
),
model: Flag.string("model").pipe(
model: Flag.String("model").pipe(
Flag.withAlias("m"),
Flag.withDescription("Model to use in the format provider/model#variant"),
Flag.optional,
),
agent: Flag.string("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
format: Flag.choice("format", ["default", "json"]).pipe(
agent: Flag.String("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
format: Flag.Literals("format", ["default", "json"]).pipe(
Flag.withDescription("Output format"),
Flag.withDefault("default"),
),
file: Flag.string("file").pipe(
file: Flag.String("file").pipe(
Flag.withAlias("f"),
Flag.withDescription("File to attach to the message"),
Flag.atMost(100),
),
title: Flag.string("title").pipe(Flag.withDescription("Session title"), Flag.optional),
thinking: Flag.boolean("thinking").pipe(Flag.withDescription("Show thinking blocks"), Flag.withDefault(false)),
title: Flag.String("title").pipe(Flag.withDescription("Session title"), Flag.optional),
thinking: Flag.Boolean("thinking").pipe(Flag.withDescription("Show thinking blocks"), Flag.withDefault(false)),
...PermissionParams,
},
}),
@@ -422,13 +422,13 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "List top-level sessions in the current project, newest first",
params: {
...ServerParams,
maxCount: Flag.integer("max-count").pipe(
maxCount: Flag.Int("max-count").pipe(
Flag.withAlias("n"),
Flag.withSchema(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))),
Flag.withDescription("Limit to N most recent sessions (default: 100)"),
Flag.optional,
),
format: Flag.choice("format", ["table", "json"]).pipe(
format: Flag.Literals("format", ["table", "json"]).pipe(
Flag.withDescription("Output format"),
Flag.withDefault("table"),
),
@@ -438,18 +438,18 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "Delete a session and its child sessions",
params: {
...ServerParams,
sessionID: Argument.string("sessionID").pipe(Argument.withDescription("Session ID to delete")),
sessionID: Argument.String("sessionID").pipe(Argument.withDescription("Session ID to delete")),
},
}),
Spec.make("export", {
description: "Export session data as JSON",
params: {
...ServerParams,
session: Argument.string("session").pipe(
session: Argument.String("session").pipe(
Argument.withDescription("Session ID to export"),
Argument.optional,
),
sanitize: Flag.boolean("sanitize").pipe(
sanitize: Flag.Boolean("sanitize").pipe(
Flag.withDescription("Redact sensitive transcript and file data"),
Flag.withDefault(false),
),
@@ -459,8 +459,8 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
description: "Import session data from a JSON file or URL",
params: {
...ServerParams,
file: Argument.string("file").pipe(Argument.withDescription("JSON file or URL to import")),
directory: Flag.string("directory").pipe(
file: Argument.String("file").pipe(Argument.withDescription("JSON file or URL to import")),
directory: Flag.String("directory").pipe(
Flag.withDescription("Directory in which to import the session"),
Flag.optional,
),
@@ -478,8 +478,8 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("get", {
description: "Get service configuration",
params: {
key: Argument.string("key").pipe(Argument.withDescription("Service setting or env"), Argument.optional),
name: Argument.string("name").pipe(
key: Argument.String("key").pipe(Argument.withDescription("Service setting or env"), Argument.optional),
name: Argument.String("name").pipe(
Argument.withDescription("Environment variable name"),
Argument.optional,
),
@@ -488,11 +488,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("set", {
description: "Set service configuration",
params: {
key: Argument.string("key").pipe(Argument.withDescription("Service setting or env")),
value: Argument.string("value").pipe(
key: Argument.String("key").pipe(Argument.withDescription("Service setting or env")),
value: Argument.String("value").pipe(
Argument.withDescription("Setting value or environment variable name"),
),
nestedValue: Argument.string("env-value").pipe(
nestedValue: Argument.String("env-value").pipe(
Argument.withDescription("Environment variable value"),
Argument.optional,
),
@@ -501,8 +501,8 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("unset", {
description: "Unset service configuration",
params: {
key: Argument.string("key").pipe(Argument.withDescription("Service setting or env")),
name: Argument.string("name").pipe(
key: Argument.String("key").pipe(Argument.withDescription("Service setting or env")),
name: Argument.String("name").pipe(
Argument.withDescription("Environment variable name"),
Argument.optional,
),
@@ -519,7 +519,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("pair", {
description: "Print one-time links to connect a browser or app",
params: {
url: Flag.string("url").pipe(
url: Flag.String("url").pipe(
Flag.withDescription("Use an external HTTP(S) server URL in pairing links"),
Flag.mapTryCatch(
(value) => {
@@ -537,15 +537,15 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
Spec.make("serve", {
description: "Start the v2 API and web server",
params: {
hostname: Flag.string("hostname").pipe(Flag.optional),
port: Flag.integer("port").pipe(Flag.optional),
cors: Flag.string("cors").pipe(
hostname: Flag.String("hostname").pipe(Flag.optional),
port: Flag.Int("port").pipe(Flag.optional),
cors: Flag.String("cors").pipe(
Flag.withSchema(Schema.NonEmptyString),
Flag.withDescription("Additional allowed CORS origin (repeat for multiple origins)"),
Flag.atLeast(0),
),
service: Flag.boolean("service").pipe(Flag.withDefault(false)),
stdio: Flag.boolean("stdio").pipe(Flag.withDefault(false)),
service: Flag.Boolean("service").pipe(Flag.withDefault(false)),
stdio: Flag.Boolean("stdio").pipe(Flag.withDefault(false)),
},
}),
],
@@ -61,7 +61,7 @@ const handler = Effect.fn("cli.session.list")(function* (
const { AppProcess } = yield* Effect.promise(() => import("@opencode/util/process"))
const { LayerNode } = yield* Effect.promise(() => import("@opencode/util/effect/layer-node"))
const { ChildProcess } = yield* Effect.promise(() => import("effect/unstable/process"))
const { ChildProcess } = yield* Effect.promise(() => import("effect/process"))
yield* Effect.gen(function* () {
const processService = yield* AppProcess.Service
const pager = yield* processService
+2 -2
View File
@@ -7,8 +7,8 @@ import { Config } from "effect"
// The opencode server password: sent by clients connecting to an explicit
// --server, and adopted by a manually run or standalone server. The legacy
// name is still honored.
export const password = Config.redacted("OPENCODE_PASSWORD").pipe(
Config.orElse(() => Config.redacted("OPENCODE_SERVER_PASSWORD")),
export const password = Config.Redacted("OPENCODE_PASSWORD").pipe(
Config.orElse(() => Config.Redacted("OPENCODE_SERVER_PASSWORD")),
Config.withDefault(undefined),
)
+1 -1
View File
@@ -1,5 +1,5 @@
import { Effect, FileSystem, Scope } from "effect"
import { Command } from "effect/unstable/cli"
import { Command } from "effect/cli"
import { PrintLogs } from "../commands/commands"
import { Spec } from "./spec"
import { Global } from "@opencode/util/global"
+1 -1
View File
@@ -1,4 +1,4 @@
import { Command } from "effect/unstable/cli"
import { Command } from "effect/cli"
type Options<Config extends Command.Command.Config, Commands extends ReadonlyArray<Any>> = {
readonly description?: string
+1 -1
View File
@@ -9,7 +9,7 @@ import { AppProcess } from "@opencode/util/process"
import { randomBytes, randomUUID } from "node:crypto"
import { Effect, Option, Redacted, Schedule, Schema } from "effect"
import { PersistentPty } from "@opencode/schema/persistent-pty"
import { HttpServer } from "effect/unstable/http"
import { HttpServer } from "effect/http"
import { Env } from "./env"
import { ServiceConfig } from "./services/service-config"
import { RetainedImage } from "./services/retained-image"
@@ -3,7 +3,7 @@ export * as ServiceRegistration from "./service-registration"
import { Service, type Info } from "@opencode/client/effect/service"
import path from "node:path"
import { Effect, FileSystem, Schedule, Schema } from "effect"
import { HttpServer } from "effect/unstable/http"
import { HttpServer } from "effect/http"
import { OPENCODE_VERSION } from "../version"
const infoJson = Schema.fromJsonString(Service.Info)
@@ -11,7 +11,7 @@ const encodeInfo = Schema.encodeEffect(infoJson)
const decodeInfo = Schema.decodeUnknownEffect(infoJson)
export const register = Effect.fnUntraced(function* (options: {
readonly address: HttpServer.Address
readonly address: HttpServer.HttpServer["Service"]["address"]
readonly password: string
readonly id: string
readonly file: string
+1 -1
View File
@@ -2,7 +2,7 @@ import { Service } from "@opencode/client/effect/service"
import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner"
import { LayerNode } from "@opencode/util/effect/layer-node"
import { Deferred, Effect, Schema, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { ChildProcess, ChildProcessSpawner } from "effect/process"
import { randomBytes } from "node:crypto"
import { selfCommand } from "../util/process"
+1 -1
View File
@@ -3,7 +3,7 @@ import { AppProcess } from "@opencode/util/process"
import { EffectFlock } from "@opencode/util/effect-flock"
import { OPENCODE_ARTIFACT, OPENCODE_CHANNEL, OPENCODE_LOCAL, OPENCODE_VERSION } from "../version"
import { Context, Duration, Effect, FileSystem, Layer, Option, Ref, Schema } from "effect"
import { ChildProcess } from "effect/unstable/process"
import { ChildProcess } from "effect/process"
import { parse, type ParseError } from "jsonc-parser"
import path from "node:path"
import { stripVTControlCharacters } from "node:util"
+1 -1
View File
@@ -1,6 +1,6 @@
import { FSUtil } from "@opencode/util/fs-util"
import { Effect, FileSystem } from "effect"
import { HttpServerError, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
import { HttpServerError, HttpServerRequest, HttpServerResponse } from "effect/http"
import { createHash } from "node:crypto"
import { load, type AssetMap } from "../app-assets"
+18 -19
View File
@@ -1,5 +1,5 @@
import { NodeSocket } from "@effect/platform-node"
import { Effect, Schema, Stdio, Stream } from "effect"
import { Effect, Option, Schema, Stdio, Stream } from "effect"
const Response = Schema.fromJsonString(Schema.Struct({ value: Schema.NullOr(Schema.String) }))
const Port = Schema.NumberFromString.check(Schema.isInt(), Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(65535))
@@ -11,25 +11,24 @@ export const askpass = Effect.gen(function* () {
const stdio = yield* Stdio.Stdio
const socket = yield* NodeSocket.makeNet({ host: "127.0.0.1", port })
const write = yield* socket.writer
const response = { text: "" }
yield* Effect.all(
[
socket.runString((text) =>
Effect.sync(() => {
response.text += text
}),
),
write(
JSON.stringify({
token: process.env.OPENCODE_SSH_ASKPASS_TOKEN,
text: process.argv.slice(2).join(" "),
confirm: process.env.SSH_ASKPASS_PROMPT === "confirm",
}) + "\n",
),
],
{ concurrency: "unbounded", discard: true },
const reader = yield* socket.reader
yield* write.write(
JSON.stringify({
token: process.env.OPENCODE_SSH_ASKPASS_TOKEN,
text: process.argv.slice(2).join(" "),
confirm: process.env.SSH_ASKPASS_PROMPT === "confirm",
}) + "\n",
)
const result = yield* Schema.decodeUnknownEffect(Response)(response.text)
const result = yield* Effect.gen(function* () {
const decoder = new TextDecoder()
let text = ""
while (true) {
const frames = yield* reader.pull
for (const frame of frames) text += typeof frame === "string" ? frame : decoder.decode(frame, { stream: true })
const result = Schema.decodeUnknownOption(Response)(text)
if (Option.isSome(result)) return result.value
}
})
if (result.value === null) return 1
yield* Stream.make(result.value + "\n").pipe(Stream.run(stdio.stdout({ endOnDone: false })))
return 0
+1 -1
View File
@@ -2,7 +2,7 @@ import { NodeServices } from "@effect/platform-node"
import { Global } from "@opencode/util/global"
import { expect, test } from "bun:test"
import { Effect, Exit, FileSystem } from "effect"
import { Command } from "effect/unstable/cli"
import { Command } from "effect/cli"
import path from "node:path"
import { Commands } from "../src/commands/commands"
import { ServiceConfig } from "../src/services/service-config"
+1 -1
View File
@@ -1,6 +1,6 @@
import { NodeServices } from "@effect/platform-node"
import { Effect } from "effect"
import { Command } from "effect/unstable/cli"
import { Command } from "effect/cli"
import { Commands } from "../../src/commands/commands"
import upgrade from "../../src/commands/handlers/upgrade"
import { Updater } from "../../src/services/updater"
+3 -2
View File
@@ -3,7 +3,8 @@ import { Service, type Info } from "@opencode/client/effect/service"
import { Global } from "@opencode/util/global"
import { OPENCODE_VERSION } from "../src/version"
import { expect, test } from "bun:test"
import { Effect, FileSystem, Schema } from "effect"
import { Effect, FileSystem, Result, Schema } from "effect"
import { NetAddress } from "effect/net"
import fs from "node:fs/promises"
import os from "node:os"
import path from "node:path"
@@ -519,7 +520,7 @@ test("service registration replaces a stale owner with the bound address", async
try {
const cleanup = await Effect.runPromise(
ServiceRegistration.register({
address: { _tag: "TcpAddress", hostname: "127.0.0.1", port: 4321 },
address: Result.getOrThrow(NetAddress.inetAddressV4(NetAddress.ipv4Loopback, 4321)),
password: "secret",
id: "owner",
file: registration,
+1 -1
View File
@@ -5,7 +5,7 @@ import { Global } from "@opencode/util/global"
import { AppProcess } from "@opencode/util/process"
import { expect, spyOn, test } from "bun:test"
import { Effect, FileSystem, Layer, PlatformError, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { ChildProcess, ChildProcessSpawner } from "effect/process"
import { existsSync, readdirSync, readFileSync } from "node:fs"
import path from "node:path"
import { Updater } from "../src/services/updater"
Loaded 100 of 394 files, more files were not shown because too many files have changed in this diff. Show more